Skip to content

Commit

Permalink
[8.x] [Search Playground] Search Preview and Document Viewer (elastic…
Browse files Browse the repository at this point in the history
…#192096) (elastic#193004)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Search Playground] Search Preview and Document Viewer
(elastic#192096)](elastic#192096)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Efe Gürkan
YALAMAN","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-09-16T12:31:38Z","message":"[Search
Playground] Search Preview and Document Viewer (elastic#192096)\n\n##
Summary\r\n\r\nAdds Search preview functionality to Search
Playground\r\nAdds Unified Document Viewer flyout to the Search
Playground\r\nAll of these code are under the same UI setting that we
had for
Search\r\nPlayground.\r\n\r\n\r\nhttps://github.com/user-attachments/assets/cd590414-b22f-4cde-a7e1-ca139aefe178\r\n\r\nThis
introduces new dependencies to the plugin, locally there was
no\r\nproblem visible (i.e. no warnings or something weird in Kibana
logs)\r\n\r\n### Checklist\r\n\r\nDelete any items that are not
applicable to this PR.\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[
]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas
added for features that require explanation or tutorials\r\n- [ ] [Unit
or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n- [ ] [Flaky
Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\r\nused on any tests changed\r\n- [x] Any UI touched in this PR is
usable by keyboard only (learn more\r\nabout [keyboard
accessibility](https://webaim.org/techniques/keyboard/))\r\n- [ ] Any UI
touched in this PR does not create any new axe failures\r\n(run axe in
browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n-
[x] This renders correctly on smaller devices using a
responsive\r\nlayout. (You can test this [in
your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n-
[x] This was checked for
[cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\r\n\r\n\r\n###
Risk Matrix\r\n\r\n\r\n| Risk | Probability | Severity |
Mitigation/Notes
|\r\n\r\n|---------------------------|-------------|----------|-------------------------|\r\n|
Potential breaking in Chat Playground Need to be tested | Low |
Medium\r\n| It should be tested by at least another person feature flag
off in\r\nChat playground both Stack and Serverless
|\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<[email protected]>","sha":"ca8e53fb3a85ba8abfcf9cc247cdcfcf30a79cef","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:EnterpriseSearch","v8.16.0"],"title":"[Search
Playground] Search Preview and Document
Viewer","number":192096,"url":"https://github.com/elastic/kibana/pull/192096","mergeCommit":{"message":"[Search
Playground] Search Preview and Document Viewer (elastic#192096)\n\n##
Summary\r\n\r\nAdds Search preview functionality to Search
Playground\r\nAdds Unified Document Viewer flyout to the Search
Playground\r\nAll of these code are under the same UI setting that we
had for
Search\r\nPlayground.\r\n\r\n\r\nhttps://github.com/user-attachments/assets/cd590414-b22f-4cde-a7e1-ca139aefe178\r\n\r\nThis
introduces new dependencies to the plugin, locally there was
no\r\nproblem visible (i.e. no warnings or something weird in Kibana
logs)\r\n\r\n### Checklist\r\n\r\nDelete any items that are not
applicable to this PR.\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[
]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas
added for features that require explanation or tutorials\r\n- [ ] [Unit
or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n- [ ] [Flaky
Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\r\nused on any tests changed\r\n- [x] Any UI touched in this PR is
usable by keyboard only (learn more\r\nabout [keyboard
accessibility](https://webaim.org/techniques/keyboard/))\r\n- [ ] Any UI
touched in this PR does not create any new axe failures\r\n(run axe in
browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n-
[x] This renders correctly on smaller devices using a
responsive\r\nlayout. (You can test this [in
your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n-
[x] This was checked for
[cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\r\n\r\n\r\n###
Risk Matrix\r\n\r\n\r\n| Risk | Probability | Severity |
Mitigation/Notes
|\r\n\r\n|---------------------------|-------------|----------|-------------------------|\r\n|
Potential breaking in Chat Playground Need to be tested | Low |
Medium\r\n| It should be tested by at least another person feature flag
off in\r\nChat playground both Stack and Serverless
|\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<[email protected]>","sha":"ca8e53fb3a85ba8abfcf9cc247cdcfcf30a79cef"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/192096","number":192096,"mergeCommit":{"message":"[Search
Playground] Search Preview and Document Viewer (elastic#192096)\n\n##
Summary\r\n\r\nAdds Search preview functionality to Search
Playground\r\nAdds Unified Document Viewer flyout to the Search
Playground\r\nAll of these code are under the same UI setting that we
had for
Search\r\nPlayground.\r\n\r\n\r\nhttps://github.com/user-attachments/assets/cd590414-b22f-4cde-a7e1-ca139aefe178\r\n\r\nThis
introduces new dependencies to the plugin, locally there was
no\r\nproblem visible (i.e. no warnings or something weird in Kibana
logs)\r\n\r\n### Checklist\r\n\r\nDelete any items that are not
applicable to this PR.\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[
]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas
added for features that require explanation or tutorials\r\n- [ ] [Unit
or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n- [ ] [Flaky
Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\r\nused on any tests changed\r\n- [x] Any UI touched in this PR is
usable by keyboard only (learn more\r\nabout [keyboard
accessibility](https://webaim.org/techniques/keyboard/))\r\n- [ ] Any UI
touched in this PR does not create any new axe failures\r\n(run axe in
browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n-
[x] This renders correctly on smaller devices using a
responsive\r\nlayout. (You can test this [in
your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n-
[x] This was checked for
[cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\r\n\r\n\r\n###
Risk Matrix\r\n\r\n\r\n| Risk | Probability | Severity |
Mitigation/Notes
|\r\n\r\n|---------------------------|-------------|----------|-------------------------|\r\n|
Potential breaking in Chat Playground Need to be tested | Low |
Medium\r\n| It should be tested by at least another person feature flag
off in\r\nChat playground both Stack and Serverless
|\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<[email protected]>","sha":"ca8e53fb3a85ba8abfcf9cc247cdcfcf30a79cef"}},{"branch":"8.x","label":"v8.16.0","branchLabelMappingKey":"^v8.16.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Efe Gürkan YALAMAN <[email protected]>
  • Loading branch information
kibanamachine and efegurkan authored Sep 16, 2024
1 parent 0e8f537 commit 831fdc1
Show file tree
Hide file tree
Showing 18 changed files with 493 additions and 87 deletions.
8 changes: 8 additions & 0 deletions x-pack/plugins/search_playground/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,16 @@
* 2.0.
*/

import { Pagination } from './types';

export const PLUGIN_ID = 'searchPlayground';
export const PLUGIN_NAME = 'Playground';
export const PLUGIN_PATH = '/app/search_playground';

export const SEARCH_MODE_FEATURE_FLAG_ID = 'searchPlayground:searchModeEnabled';

export const DEFAULT_PAGINATION: Pagination = {
from: 0,
size: 10,
total: 0,
};
7 changes: 7 additions & 0 deletions x-pack/plugins/search_playground/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export enum APIRoutes {
POST_CHAT_MESSAGE = '/internal/search_playground/chat',
POST_QUERY_SOURCE_FIELDS = '/internal/search_playground/query_source_fields',
GET_INDICES = '/internal/search_playground/indices',
POST_SEARCH_QUERY = '/internal/search_playground/search',
}

export enum LLMs {
Expand Down Expand Up @@ -82,3 +83,9 @@ export interface ModelProvider {
promptTokenLimit: number;
provider: LLMs;
}

export interface Pagination {
from: number;
size: number;
total: number;
}
4 changes: 3 additions & 1 deletion x-pack/plugins/search_playground/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
],
"requiredPlugins": [
"actions",
"data",
"encryptedSavedObjects",
"navigation",
"share",
Expand All @@ -25,7 +26,8 @@
"usageCollection",
],
"requiredBundles": [
"kibanaReact"
"kibanaReact",
"unifiedDocViewer"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export const Header: React.FC<HeaderProps> = ({
<EuiPageHeaderSection>
<EuiFlexGroup alignItems="center">
{showDocs && <PlaygroundHeaderDocs />}
<Toolbar />
<Toolbar selectedPageMode={selectedPageMode} />
</EuiFlexGroup>
</EuiPageHeaderSection>
</EuiPageTemplate.Header>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';

import { EuiEmptyPrompt } from '@elastic/eui';
import { i18n } from '@kbn/i18n';

export interface EmptyResultsArgs {
query?: string;
}

export const EmptyResults: React.FC<EmptyResultsArgs> = ({ query }) => {
return (
<EuiEmptyPrompt
body={
<p>
{query
? i18n.translate('xpack.searchPlayground.resultList.emptyWithQuery.text', {
defaultMessage: 'No result found for: {query}',
values: { query },
})
: i18n.translate('xpack.searchPlayground.resultList.empty.text', {
defaultMessage: 'No results found',
})}
</p>
}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,54 +5,117 @@
* 2.0.
*/

import React, { useEffect, useState } from 'react';

import {
EuiFlexGroup,
EuiFlexItem,
EuiHorizontalRule,
EuiPagination,
EuiPanel,
EuiText,
EuiTitle,
} from '@elastic/eui';
import React from 'react';

const DEMO_DATA = [
{ id: '123321', name: 'John Doe', age: 25 },
{ id: '123321', name: 'John Doe', age: 25 },
{ id: '123321', name: 'John Doe', age: 25 },
{ id: '123321', name: 'John Doe', age: 25 },
{ id: '123321', name: 'John Doe', age: 25 },
{ id: '123321', name: 'John Doe', age: 25 },
{ id: '123321', name: 'John Doe', age: 25 },
{ id: '123321', name: 'John Doe', age: 25 },
{ id: '123321', name: 'John Doe', age: 25 },
{ id: '123321', name: 'John Doe', age: 25 },
];
import { UnifiedDocViewerFlyout } from '@kbn/unified-doc-viewer-plugin/public';

import type { DataView } from '@kbn/data-views-plugin/public';
import type { EsHitRecord } from '@kbn/discover-utils/types';
import type { SearchHit } from '@elastic/elasticsearch/lib/api/types';
import { buildDataTableRecord } from '@kbn/discover-utils';
import { i18n } from '@kbn/i18n';
import { Pagination } from '../../types';
import { getPageCounts } from '../../utils/pagination_helper';
import { EmptyResults } from './empty_results';
import { useKibana } from '../../hooks/use_kibana';

export interface ResultListArgs {
searchResults: SearchHit[];
pagination: Pagination;
onPaginationChange: (nextPage: number) => void;
searchQuery?: string;
}

export const ResultList: React.FC = () => {
export const ResultList: React.FC<ResultListArgs> = ({
searchResults,
pagination,
onPaginationChange,
searchQuery = '',
}) => {
const {
services: { data },
} = useKibana();
const [dataView, setDataView] = useState<DataView | null>(null);
useEffect(() => {
data.dataViews.getDefaultDataView().then((d) => setDataView(d));
}, [data]);
const [flyoutDocId, setFlyoutDocId] = useState<string | undefined>(undefined);
const { totalPage, page } = getPageCounts(pagination);
const hit =
flyoutDocId &&
buildDataTableRecord(searchResults.find((item) => item._id === flyoutDocId) as EsHitRecord);
return (
<EuiPanel grow={false}>
<EuiFlexGroup direction="column" gutterSize="none">
{DEMO_DATA.map((item, index) => {
return (
<>
<EuiFlexItem key={item.id + '-' + index} grow>
<EuiFlexGroup direction="column" gutterSize="xs">
<EuiFlexItem grow>
<EuiTitle size="xs">
<h2>{item.id}</h2>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow>
<EuiText size="s">
<p>{item.name}</p>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
{index !== DEMO_DATA.length - 1 && <EuiHorizontalRule margin="m" />}
</>
);
})}
{searchResults.length === 0 && (
<EuiFlexItem>
<EmptyResults query={searchQuery} />
</EuiFlexItem>
)}
{searchResults.length !== 0 &&
searchResults.map((item, index) => {
return (
<>
<EuiFlexItem
key={item._id + '-' + index}
onClick={() => setFlyoutDocId(item._id)}
grow
>
<EuiFlexGroup direction="column" gutterSize="xs">
<EuiFlexItem grow>
<EuiTitle size="xs">
<h3>ID:{item._id}</h3>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow>
<EuiText size="s">
<p>
{i18n.translate('xpack.searchPlayground.resultList.result.score', {
defaultMessage: 'Document score: {score}',
values: { score: item._score },
})}
</p>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
{index !== searchResults.length - 1 && <EuiHorizontalRule margin="m" />}
</>
);
})}
{searchResults.length !== 0 && (
<EuiFlexItem>
<EuiPagination
pageCount={totalPage}
activePage={page}
onPageClick={onPaginationChange}
/>
</EuiFlexItem>
)}
{flyoutDocId && dataView && hit && (
<UnifiedDocViewerFlyout
services={{}}
onClose={() => setFlyoutDocId(undefined)}
isEsqlQuery={false}
columns={[]}
hit={hit}
dataView={dataView}
onAddColumn={() => {}}
onRemoveColumn={() => {}}
setExpandedDoc={() => {}}
flyoutType="overlay"
/>
)}
</EuiFlexGroup>
</EuiPanel>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,50 @@
*/

import {
EuiButton,
EuiEmptyPrompt,
EuiFieldText,
EuiFlexGroup,
EuiFlexItem,
EuiSearchBar,
EuiForm,
useEuiTheme,
} from '@elastic/eui';
import React from 'react';
import { css } from '@emotion/react';
import { Controller, useController, useFormContext } from 'react-hook-form';
import { i18n } from '@kbn/i18n';
import { useQueryClient } from '@tanstack/react-query';
import { DEFAULT_PAGINATION } from '../../../common';
import { ResultList } from './result_list';
import { ChatForm, ChatFormFields, Pagination } from '../../types';
import { useSearchPreview } from '../../hooks/use_search_preview';
import { getPaginationFromPage } from '../../utils/pagination_helper';

export const SearchMode: React.FC = () => {
const { euiTheme } = useEuiTheme();
const showResults = true; // TODO demo
const { control, handleSubmit } = useFormContext();
const {
field: { value: searchBarValue },
formState: { isSubmitting },
} = useController<ChatForm, ChatFormFields.searchQuery>({
name: ChatFormFields.searchQuery,
});

const [searchQuery, setSearchQuery] = React.useState<{
query: string;
pagination: Pagination;
}>({ query: searchBarValue, pagination: DEFAULT_PAGINATION });

const { results, pagination } = useSearchPreview(searchQuery);

const queryClient = useQueryClient();
const handleSearch = async (query = searchBarValue, paginationParam = DEFAULT_PAGINATION) => {
queryClient.resetQueries({ queryKey: ['search-preview-results'] });
setSearchQuery({ query, pagination: paginationParam });
};

const onPagination = (page: number) => {
handleSearch(searchBarValue, getPaginationFromPage(page, pagination.size, pagination));
};

return (
<EuiFlexGroup direction="row" justifyContent="center">
Expand All @@ -31,25 +61,55 @@ export const SearchMode: React.FC = () => {
>
<EuiFlexGroup direction="column">
<EuiFlexItem grow={false}>
<EuiSearchBar />
<EuiForm component="form" onSubmit={handleSubmit(() => handleSearch())}>
<Controller
control={control}
name={ChatFormFields.searchQuery}
render={({ field }) => (
<EuiFieldText
{...field}
value={searchBarValue}
icon="search"
fullWidth
placeholder={i18n.translate(
'xpack.searchPlayground.searchMode.searchBar.placeholder',
{ defaultMessage: 'Search for documents' }
)}
isLoading={isSubmitting}
/>
)}
/>
</EuiForm>
</EuiFlexItem>
<EuiFlexItem className="eui-yScroll">
<EuiFlexGroup direction="column">
<EuiFlexItem>
{showResults ? (
<ResultList />
{searchQuery.query ? (
<ResultList
searchResults={results}
pagination={pagination}
onPaginationChange={onPagination}
searchQuery={searchQuery.query}
/>
) : (
<EuiEmptyPrompt
iconType={'checkInCircleFilled'}
iconColor="success"
title={<h2>Ready to search</h2>}
title={
<h2>
{i18n.translate('xpack.searchPlayground.searchMode.readyToSearch', {
defaultMessage: 'Ready to search',
})}
</h2>
}
body={
<p>
Type in a query in the search bar above or view the query we automatically
created for you.
{i18n.translate('xpack.searchPlayground.searchMode.searchPrompt', {
defaultMessage:
'Type in a query in the search bar above or view the query we automatically created for you.',
})}
</p>
}
actions={<EuiButton>View the query</EuiButton>}
/>
)}
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ import { EuiFlexGroup } from '@elastic/eui';
import React from 'react';
import { DataActionButton } from './data_action_button';
import { ViewCodeAction } from './view_code/view_code_action';
import { PlaygroundPageMode } from '../types';

export const Toolbar: React.FC = () => {
export const Toolbar: React.FC<{ selectedPageMode: PlaygroundPageMode }> = ({
selectedPageMode = PlaygroundPageMode.chat,
}) => {
return (
<EuiFlexGroup gutterSize="s" alignItems="center" data-test-subj="playground-header-actions">
<DataActionButton />
<ViewCodeAction />
<ViewCodeAction selectedPageMode={selectedPageMode} />
</EuiFlexGroup>
);
};
Loading

0 comments on commit 831fdc1

Please sign in to comment.