mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
Query builder base page (#190091)
## Summary Adds the base Search Playground behind a feature flag. This will be used to create new Search Playground page mode that is used for queries rather than LLMs <img width="1533" alt="Screenshot 2024-08-13 at 16 00 32" src="https://github.com/user-attachments/assets/d1c78ef2-88c0-4c67-bbdd-2704142b95df"> <img width="1523" alt="Screenshot 2024-08-13 at 16 00 41" src="https://github.com/user-attachments/assets/01b3b3cb-95e4-4a09-a07d-069d810cf42c"> ### Checklist Delete any items that are not applicable to this PR. - [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) - [ ] [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 - [x] 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 was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers)
This commit is contained in:
parent
8f39bdfe25
commit
1949de076a
19 changed files with 414 additions and 38 deletions
|
@ -152,7 +152,12 @@ export const renderApp = (
|
|||
ReactDOM.render(
|
||||
<I18nProvider>
|
||||
<KibanaThemeProvider theme={{ theme$: params.theme$ }}>
|
||||
<KibanaContextProvider services={{ ...core, ...plugins }}>
|
||||
<KibanaContextProvider
|
||||
services={{
|
||||
...core,
|
||||
...plugins,
|
||||
}}
|
||||
>
|
||||
<CloudContext>
|
||||
<Provider store={store}>
|
||||
<Router history={params.history}>
|
||||
|
|
|
@ -68,8 +68,8 @@ export interface KibanaLogicProps {
|
|||
productFeatures: ProductFeatures;
|
||||
renderHeaderActions(HeaderActions?: FC): void;
|
||||
searchHomepage?: SearchHomepagePluginStart;
|
||||
searchPlayground?: SearchPlaygroundPluginStart;
|
||||
searchInferenceEndpoints?: SearchInferenceEndpointsPluginStart;
|
||||
searchPlayground?: SearchPlaygroundPluginStart;
|
||||
security?: SecurityPluginStart;
|
||||
setBreadcrumbs(crumbs: ChromeBreadcrumb[]): void;
|
||||
setChromeIsVisible(isVisible: boolean): void;
|
||||
|
@ -103,8 +103,8 @@ export interface KibanaValues {
|
|||
productFeatures: ProductFeatures;
|
||||
renderHeaderActions(HeaderActions?: FC): void;
|
||||
searchHomepage: SearchHomepagePluginStart | null;
|
||||
searchPlayground: SearchPlaygroundPluginStart | null;
|
||||
searchInferenceEndpoints: SearchInferenceEndpointsPluginStart | null;
|
||||
searchPlayground: SearchPlaygroundPluginStart | null;
|
||||
security: SecurityPluginStart | null;
|
||||
setBreadcrumbs(crumbs: ChromeBreadcrumb[]): void;
|
||||
setChromeIsVisible(isVisible: boolean): void;
|
||||
|
@ -150,8 +150,8 @@ export const KibanaLogic = kea<MakeLogicType<KibanaValues>>({
|
|||
productFeatures: [props.productFeatures, {}],
|
||||
renderHeaderActions: [props.renderHeaderActions, {}],
|
||||
searchHomepage: [props.searchHomepage || null, {}],
|
||||
searchPlayground: [props.searchPlayground || null, {}],
|
||||
searchInferenceEndpoints: [props.searchInferenceEndpoints || null, {}],
|
||||
searchPlayground: [props.searchPlayground || null, {}],
|
||||
security: [props.security || null, {}],
|
||||
setBreadcrumbs: [props.setBreadcrumbs, {}],
|
||||
setChromeIsVisible: [props.setChromeIsVisible, {}],
|
||||
|
|
|
@ -7,3 +7,6 @@
|
|||
|
||||
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';
|
||||
|
|
|
@ -22,12 +22,15 @@ export enum AnalyticsEvents {
|
|||
includeCitations = 'include_citations',
|
||||
instructionsFieldChanged = 'instructions_field_changed',
|
||||
queryFieldsUpdated = 'view_query_fields_updated',
|
||||
queryBuilderFieldsUpdated = 'view_search_fields_updated',
|
||||
queryModeLoaded = 'query_mode_loaded',
|
||||
queryBuilderModeLoaded = 'search_builder_mode_loaded',
|
||||
modelSelected = 'model_selected',
|
||||
retrievalDocsFlyoutOpened = 'retrieval_docs_flyout_opened',
|
||||
sourceFieldsLoaded = 'source_fields_loaded',
|
||||
sourceIndexUpdated = 'source_index_updated',
|
||||
setupChatPageLoaded = 'start_new_chat_page_loaded',
|
||||
setupSearchPageLoaded = 'search_setup_page_loaded',
|
||||
viewCodeFlyoutOpened = 'view_code_flyout_opened',
|
||||
viewCodeLanguageChange = 'view_code_language_change',
|
||||
}
|
||||
|
|
|
@ -5,19 +5,23 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
|
||||
|
||||
import { useWatch } from 'react-hook-form';
|
||||
import { QueryMode } from './query_mode/query_mode';
|
||||
import { SetupPage } from './setup_page/setup_page';
|
||||
import { ChatSetupPage } from './setup_page/chat_setup_page';
|
||||
import { Header } from './header';
|
||||
import { useLoadConnectors } from '../hooks/use_load_connectors';
|
||||
import { ChatForm, ChatFormFields } from '../types';
|
||||
import { ChatForm, ChatFormFields, PlaygroundPageMode } from '../types';
|
||||
import { Chat } from './chat';
|
||||
import { SearchMode } from './search_mode/search_mode';
|
||||
import { SearchPlaygroundSetupPage } from './setup_page/search_playground_setup_page';
|
||||
import { usePageMode } from '../hooks/use_page_mode';
|
||||
|
||||
export interface AppProps {
|
||||
showDocs?: boolean;
|
||||
pageMode?: PlaygroundPageMode;
|
||||
}
|
||||
|
||||
export enum ViewMode {
|
||||
|
@ -25,22 +29,65 @@ export enum ViewMode {
|
|||
query = 'query',
|
||||
}
|
||||
|
||||
export const App: React.FC<AppProps> = ({ showDocs = false }) => {
|
||||
const [showSetupPage, setShowSetupPage] = useState(true);
|
||||
export const App: React.FC<AppProps> = ({
|
||||
showDocs = false,
|
||||
pageMode = PlaygroundPageMode.chat,
|
||||
}) => {
|
||||
const [selectedMode, setSelectedMode] = useState<ViewMode>(ViewMode.chat);
|
||||
const { data: connectors } = useLoadConnectors();
|
||||
const hasSelectedIndices = useWatch<ChatForm, ChatFormFields.indices>({
|
||||
name: ChatFormFields.indices,
|
||||
}).length;
|
||||
const handleModeChange = (id: string) => setSelectedMode(id as ViewMode);
|
||||
const hasSelectedIndices = Boolean(
|
||||
useWatch<ChatForm, ChatFormFields.indices>({
|
||||
name: ChatFormFields.indices,
|
||||
}).length
|
||||
);
|
||||
const handleModeChange = (id: ViewMode) => setSelectedMode(id);
|
||||
const handlePageModeChange = (mode: PlaygroundPageMode) => setSelectedPageMode(mode);
|
||||
const {
|
||||
showSetupPage,
|
||||
pageMode: selectedPageMode,
|
||||
setPageMode: setSelectedPageMode,
|
||||
} = usePageMode({
|
||||
hasSelectedIndices,
|
||||
hasConnectors: Boolean(connectors?.length),
|
||||
initialPageMode: pageMode,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (showSetupPage && connectors?.length && hasSelectedIndices) {
|
||||
setShowSetupPage(false);
|
||||
} else if (!showSetupPage && (!connectors?.length || !hasSelectedIndices)) {
|
||||
setShowSetupPage(true);
|
||||
}
|
||||
}, [connectors, hasSelectedIndices, showSetupPage]);
|
||||
const restrictedWidth = selectedPageMode === PlaygroundPageMode.search && selectedMode === 'chat';
|
||||
const paddingSize =
|
||||
selectedPageMode === PlaygroundPageMode.search && selectedMode === 'chat' ? 'xl' : 'none';
|
||||
|
||||
const getSetupPage = () => {
|
||||
return (
|
||||
showSetupPage && (
|
||||
<>
|
||||
{selectedPageMode === PlaygroundPageMode.chat && <ChatSetupPage />}
|
||||
{selectedPageMode === PlaygroundPageMode.search && <SearchPlaygroundSetupPage />}
|
||||
</>
|
||||
)
|
||||
);
|
||||
};
|
||||
const getQueryBuilderPage = () => {
|
||||
return (
|
||||
!showSetupPage &&
|
||||
selectedPageMode === PlaygroundPageMode.search && (
|
||||
<>
|
||||
{selectedMode === ViewMode.chat && <SearchMode />}
|
||||
{selectedMode === ViewMode.query && <QueryMode />}
|
||||
</>
|
||||
)
|
||||
);
|
||||
};
|
||||
const getChatPage = () => {
|
||||
return (
|
||||
!showSetupPage &&
|
||||
selectedPageMode === PlaygroundPageMode.chat && (
|
||||
<>
|
||||
{selectedMode === ViewMode.chat && <Chat />}
|
||||
{selectedMode === ViewMode.query && <QueryMode />}
|
||||
</>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -49,19 +96,23 @@ export const App: React.FC<AppProps> = ({ showDocs = false }) => {
|
|||
onModeChange={handleModeChange}
|
||||
selectedMode={selectedMode}
|
||||
isActionsDisabled={showSetupPage}
|
||||
selectedPageMode={selectedPageMode}
|
||||
onSelectPageModeChange={handlePageModeChange}
|
||||
/>
|
||||
<KibanaPageTemplate.Section
|
||||
alignment="top"
|
||||
restrictWidth={false}
|
||||
restrictWidth={restrictedWidth}
|
||||
grow
|
||||
css={{
|
||||
position: 'relative',
|
||||
}}
|
||||
contentProps={{ css: { display: 'flex', flexGrow: 1, position: 'absolute', inset: 0 } }}
|
||||
paddingSize="none"
|
||||
paddingSize={paddingSize}
|
||||
className="eui-fullHeight"
|
||||
>
|
||||
{showSetupPage ? <SetupPage /> : selectedMode === ViewMode.chat ? <Chat /> : <QueryMode />}
|
||||
{getSetupPage()}
|
||||
{getChatPage()}
|
||||
{getQueryBuilderPage()}
|
||||
</KibanaPageTemplate.Section>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
EuiFlexGroup,
|
||||
EuiPageHeaderSection,
|
||||
EuiPageTemplate,
|
||||
EuiSelect,
|
||||
EuiTitle,
|
||||
useEuiTheme,
|
||||
} from '@elastic/eui';
|
||||
|
@ -20,11 +21,15 @@ import React from 'react';
|
|||
import { PlaygroundHeaderDocs } from './playground_header_docs';
|
||||
import { Toolbar } from './toolbar';
|
||||
import { ViewMode } from './app';
|
||||
import { PlaygroundPageMode } from '../types';
|
||||
import { useSearchPlaygroundFeatureFlag } from '../hooks/use_search_playground_feature_flag';
|
||||
|
||||
interface HeaderProps {
|
||||
showDocs?: boolean;
|
||||
selectedMode: string;
|
||||
onModeChange: (mode: string) => void;
|
||||
onModeChange: (mode: ViewMode) => void;
|
||||
selectedPageMode: PlaygroundPageMode;
|
||||
onSelectPageModeChange: (mode: PlaygroundPageMode) => void;
|
||||
isActionsDisabled?: boolean;
|
||||
}
|
||||
|
||||
|
@ -33,7 +38,10 @@ export const Header: React.FC<HeaderProps> = ({
|
|||
onModeChange,
|
||||
showDocs = false,
|
||||
isActionsDisabled = false,
|
||||
selectedPageMode,
|
||||
onSelectPageModeChange,
|
||||
}) => {
|
||||
const isSearchModeEnabled = useSearchPlaygroundFeatureFlag();
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const options = [
|
||||
{
|
||||
|
@ -72,6 +80,18 @@ export const Header: React.FC<HeaderProps> = ({
|
|||
<FormattedMessage id="xpack.searchPlayground.pageTitle" defaultMessage="Playground" />
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
{isSearchModeEnabled && (
|
||||
<EuiSelect
|
||||
data-test-subj="page-mode-select"
|
||||
options={[
|
||||
{ value: 'chat', text: 'Chat' },
|
||||
{ value: 'search', text: 'Search' },
|
||||
]}
|
||||
value={selectedPageMode}
|
||||
onChange={(e) => onSelectPageModeChange(e.target.value as PlaygroundPageMode)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<EuiBetaBadge
|
||||
label={i18n.translate('xpack.searchPlayground.pageTitle.techPreview', {
|
||||
defaultMessage: 'TECH PREVIEW',
|
||||
|
@ -86,7 +106,7 @@ export const Header: React.FC<HeaderProps> = ({
|
|||
legend="viewMode"
|
||||
options={options}
|
||||
idSelected={selectedMode}
|
||||
onChange={onModeChange}
|
||||
onChange={(id: string) => onModeChange(id as ViewMode)}
|
||||
buttonSize="compressed"
|
||||
isDisabled={isActionsDisabled}
|
||||
data-test-subj="viewModeSelector"
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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 {
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiHorizontalRule,
|
||||
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 },
|
||||
];
|
||||
|
||||
export const ResultList: React.FC = () => {
|
||||
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" />}
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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 {
|
||||
EuiButton,
|
||||
EuiEmptyPrompt,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiSearchBar,
|
||||
useEuiTheme,
|
||||
} from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { ResultList } from './result_list';
|
||||
|
||||
export const SearchMode: React.FC = () => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const showResults = true; // TODO demo
|
||||
|
||||
return (
|
||||
<EuiFlexGroup direction="row" justifyContent="center">
|
||||
<EuiFlexItem
|
||||
grow
|
||||
css={css`
|
||||
max-width: ${euiTheme.base * 48}px;
|
||||
`}
|
||||
>
|
||||
<EuiFlexGroup direction="column">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiSearchBar />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem className="eui-yScroll">
|
||||
<EuiFlexGroup direction="column">
|
||||
<EuiFlexItem>
|
||||
{showResults ? (
|
||||
<ResultList />
|
||||
) : (
|
||||
<EuiEmptyPrompt
|
||||
iconType={'checkInCircleFilled'}
|
||||
iconColor="success"
|
||||
title={<h2>Ready to search</h2>}
|
||||
body={
|
||||
<p>
|
||||
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>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
};
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import {
|
||||
EuiEmptyPrompt,
|
||||
EuiFlexGroup,
|
||||
|
@ -13,17 +15,16 @@ import {
|
|||
EuiLoadingSpinner,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import React, { useEffect } from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { CreateIndexButton } from './create_index_button';
|
||||
import { useQueryIndices } from '../../hooks/use_query_indices';
|
||||
import { docLinks } from '../../../common/doc_links';
|
||||
import { useUsageTracker } from '../../hooks/use_usage_tracker';
|
||||
import { AnalyticsEvents } from '../../analytics/constants';
|
||||
import { ConnectLLMButton } from './connect_llm_button';
|
||||
import { AddDataSources } from './add_data_sources';
|
||||
import { ConnectLLMButton } from './connect_llm_button';
|
||||
import { CreateIndexButton } from './create_index_button';
|
||||
|
||||
export const SetupPage: React.FC = () => {
|
||||
export const ChatSetupPage: React.FC = () => {
|
||||
const usageTracker = useUsageTracker();
|
||||
const { indices, isLoading: isIndicesLoading } = useQueryIndices();
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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, { useEffect } from 'react';
|
||||
|
||||
import {
|
||||
EuiEmptyPrompt,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiLink,
|
||||
EuiLoadingSpinner,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { useQueryIndices } from '../../hooks/use_query_indices';
|
||||
import { useUsageTracker } from '../../hooks/use_usage_tracker';
|
||||
import { AnalyticsEvents } from '../../analytics/constants';
|
||||
import { AddDataSources } from './add_data_sources';
|
||||
|
||||
export const SearchPlaygroundSetupPage: React.FC = () => {
|
||||
const usageTracker = useUsageTracker();
|
||||
const { isLoading: isIndicesLoading } = useQueryIndices();
|
||||
|
||||
useEffect(() => {
|
||||
usageTracker?.load(AnalyticsEvents.setupSearchPageLoaded);
|
||||
}, [usageTracker]);
|
||||
|
||||
return (
|
||||
<EuiEmptyPrompt
|
||||
iconType="indexOpen"
|
||||
data-test-subj="setupPage"
|
||||
title={
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="xpack.searchPlayground.setupPage.queryBuilder.title"
|
||||
defaultMessage="Add data to query"
|
||||
/>
|
||||
</h2>
|
||||
}
|
||||
actions={
|
||||
<EuiFlexGroup justifyContent="center">
|
||||
{isIndicesLoading ? (
|
||||
<EuiLoadingSpinner />
|
||||
) : (
|
||||
<EuiFlexItem grow={false}>
|
||||
<AddDataSources />
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
}
|
||||
footer={
|
||||
<>
|
||||
<EuiTitle size="xxs">
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id="xpack.searchPlayground.setupPage.learnMore"
|
||||
defaultMessage="Want to learn more?"
|
||||
/>
|
||||
</span>
|
||||
</EuiTitle>{' '}
|
||||
<EuiLink href="todo" target="_blank" external>
|
||||
<FormattedMessage
|
||||
id="xpack.searchPlayground.setupPage.documentationLink"
|
||||
defaultMessage="Read documentation"
|
||||
/>
|
||||
</EuiLink>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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 { useEffect, useState } from 'react';
|
||||
import { PlaygroundPageMode } from '../types';
|
||||
|
||||
export const usePageMode = ({
|
||||
hasSelectedIndices,
|
||||
hasConnectors,
|
||||
initialPageMode = PlaygroundPageMode.chat,
|
||||
}: {
|
||||
hasSelectedIndices: boolean;
|
||||
hasConnectors: boolean;
|
||||
initialPageMode?: PlaygroundPageMode;
|
||||
}) => {
|
||||
const [showSetupPage, setShowSetupPage] = useState(true);
|
||||
const [pageMode, setPageMode] = useState<PlaygroundPageMode>(initialPageMode);
|
||||
|
||||
useEffect(() => {
|
||||
if (pageMode === PlaygroundPageMode.chat) {
|
||||
if (showSetupPage && hasConnectors && hasSelectedIndices) {
|
||||
setShowSetupPage(false);
|
||||
} else if (!showSetupPage && (!hasConnectors || !hasSelectedIndices)) {
|
||||
setShowSetupPage(true);
|
||||
}
|
||||
} else {
|
||||
if (showSetupPage && hasSelectedIndices) {
|
||||
setShowSetupPage(false);
|
||||
} else if (!showSetupPage && !hasSelectedIndices) {
|
||||
setShowSetupPage(true);
|
||||
}
|
||||
}
|
||||
}, [hasSelectedIndices, showSetupPage, pageMode, hasConnectors]);
|
||||
|
||||
return {
|
||||
showSetupPage,
|
||||
pageMode,
|
||||
setPageMode,
|
||||
};
|
||||
};
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* 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 { isSearchModeEnabled } from '../utils/feature_flags';
|
||||
import { useKibana } from './use_kibana';
|
||||
|
||||
export const useSearchPlaygroundFeatureFlag = (): boolean => {
|
||||
const { uiSettings } = useKibana().services;
|
||||
|
||||
return uiSettings ? isSearchModeEnabled(uiSettings) : false;
|
||||
};
|
|
@ -9,10 +9,16 @@ import React, { useMemo } from 'react';
|
|||
import { EuiPageTemplate } from '@elastic/eui';
|
||||
import { PlaygroundProvider } from './providers/playground_provider';
|
||||
|
||||
import { App } from './components/app';
|
||||
import { useKibana } from './hooks/use_kibana';
|
||||
import { PlaygroundPageMode } from './types';
|
||||
import { App } from './components/app';
|
||||
|
||||
export const ChatPlaygroundOverview: React.FC = () => {
|
||||
interface PlaygroundOverviewProps {
|
||||
pageMode?: PlaygroundPageMode;
|
||||
}
|
||||
export const PlaygroundOverview: React.FC<PlaygroundOverviewProps> = ({
|
||||
pageMode = PlaygroundPageMode.chat,
|
||||
}) => {
|
||||
const {
|
||||
services: { console: consolePlugin },
|
||||
} = useKibana();
|
||||
|
@ -31,7 +37,7 @@ export const ChatPlaygroundOverview: React.FC = () => {
|
|||
grow={false}
|
||||
panelled={false}
|
||||
>
|
||||
<App showDocs />
|
||||
<App showDocs pageMode={pageMode} />
|
||||
{embeddableConsole}
|
||||
</EuiPageTemplate>
|
||||
</PlaygroundProvider>
|
|
@ -8,17 +8,26 @@
|
|||
import { Route, Routes } from '@kbn/shared-ux-router';
|
||||
import React from 'react';
|
||||
import { Redirect } from 'react-router-dom';
|
||||
import { ChatPlaygroundOverview } from './chat_playground_overview';
|
||||
import { PlaygroundOverview } from './playground_overview';
|
||||
|
||||
import { ROOT_PATH, SEARCH_PLAYGROUND_CHAT_PATH } from './routes';
|
||||
import { ROOT_PATH, SEARCH_PLAYGROUND_CHAT_PATH, SEARCH_PLAYGROUND_SEARCH_PATH } from './routes';
|
||||
import { PlaygroundPageMode } from './types';
|
||||
import { useSearchPlaygroundFeatureFlag } from './hooks/use_search_playground_feature_flag';
|
||||
|
||||
export const PlaygroundRouter: React.FC = () => {
|
||||
const isSearchModeEnabled = useSearchPlaygroundFeatureFlag();
|
||||
|
||||
return (
|
||||
<Routes>
|
||||
<Redirect exact from={ROOT_PATH} to={SEARCH_PLAYGROUND_CHAT_PATH} />
|
||||
<Route path={SEARCH_PLAYGROUND_CHAT_PATH}>
|
||||
<ChatPlaygroundOverview />
|
||||
<PlaygroundOverview pageMode={PlaygroundPageMode.chat} />
|
||||
</Route>
|
||||
{isSearchModeEnabled && (
|
||||
<Route path={SEARCH_PLAYGROUND_SEARCH_PATH}>
|
||||
<PlaygroundOverview pageMode={PlaygroundPageMode.search} />
|
||||
</Route>
|
||||
)}
|
||||
</Routes>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@ import type {
|
|||
AppMountParameters,
|
||||
PluginInitializerContext,
|
||||
} from '@kbn/core/public';
|
||||
import { PLUGIN_ID, PLUGIN_NAME } from '../common';
|
||||
import { PLUGIN_ID, PLUGIN_NAME, PLUGIN_PATH } from '../common';
|
||||
import { docLinks } from '../common/doc_links';
|
||||
import { PlaygroundHeaderDocs } from './components/playground_header_docs';
|
||||
import { Playground, getPlaygroundProvider } from './embeddable';
|
||||
|
@ -42,7 +42,7 @@ export class SearchPlaygroundPlugin
|
|||
|
||||
core.application.register({
|
||||
id: PLUGIN_ID,
|
||||
appRoute: '/app/search_playground',
|
||||
appRoute: PLUGIN_PATH,
|
||||
title: PLUGIN_NAME,
|
||||
async mount({ element, history }: AppMountParameters) {
|
||||
const { renderApp } = await import('./application');
|
||||
|
|
|
@ -5,5 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export const SEARCH_PLAYGROUND_APP_ID = `search_playground`;
|
||||
export const ROOT_PATH = '/';
|
||||
|
||||
export const SEARCH_PLAYGROUND_CHAT_PATH = `${ROOT_PATH}chat`;
|
||||
export const SEARCH_PLAYGROUND_SEARCH_PATH = `${ROOT_PATH}search`;
|
||||
|
|
|
@ -28,6 +28,11 @@ import { PlaygroundHeaderDocs } from './components/playground_header_docs';
|
|||
|
||||
export * from '../common/types';
|
||||
|
||||
export enum PlaygroundPageMode {
|
||||
chat = 'chat',
|
||||
search = 'search',
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface SearchPlaygroundPluginSetup {}
|
||||
export interface SearchPlaygroundPluginStart {
|
||||
|
@ -57,6 +62,9 @@ export interface AppServicesContext {
|
|||
triggersActionsUi: TriggersAndActionsUIPublicPluginStart;
|
||||
usageCollection?: UsageCollectionStart;
|
||||
console?: ConsolePluginStart;
|
||||
featureFlags: {
|
||||
searchPlaygroundEnabled: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export enum ChatFormFields {
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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 { IUiSettingsClient } from '@kbn/core/public';
|
||||
import { SEARCH_MODE_FEATURE_FLAG_ID } from '../../common';
|
||||
|
||||
export function isSearchModeEnabled(uiSettings: IUiSettingsClient): boolean {
|
||||
return uiSettings.get<boolean>(SEARCH_MODE_FEATURE_FLAG_ID, false);
|
||||
}
|
|
@ -59,7 +59,6 @@ export function defineRoutes({
|
|||
},
|
||||
errorHandler(logger)(async (context, request, response) => {
|
||||
const { client } = (await context.core).elasticsearch;
|
||||
|
||||
const { indices } = request.body;
|
||||
|
||||
const fields = await fetchFields(client, indices);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue