mirror of
https://github.com/elastic/kibana.git
synced 2025-04-19 15:35:00 -04:00
refactor(search_playground): prep for saved playgrounds (#217251)
## Summary Renaming types and files as well as moving providers around to make implmentating saved playground routes more straightforward. Naming updates to reduce future confusion from generic names that didn't fit when there are multiple providers etc.
This commit is contained in:
parent
3485e52340
commit
0f79990912
42 changed files with 297 additions and 303 deletions
|
@ -7,12 +7,14 @@
|
|||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { QueryClientProvider } from '@tanstack/react-query';
|
||||
import { CoreStart } from '@kbn/core/public';
|
||||
import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';
|
||||
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
|
||||
import { I18nProvider } from '@kbn/i18n-react';
|
||||
import { Router } from '@kbn/shared-ux-router';
|
||||
import { AppPluginStartDependencies } from './types';
|
||||
import { queryClient } from './utils/query_client';
|
||||
|
||||
export const renderApp = async (
|
||||
core: CoreStart,
|
||||
|
@ -26,7 +28,9 @@ export const renderApp = async (
|
|||
<KibanaContextProvider services={{ ...core, ...services }}>
|
||||
<I18nProvider>
|
||||
<Router history={services.history}>
|
||||
<PlaygroundRouter />
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<PlaygroundRouter />
|
||||
</QueryClientProvider>
|
||||
</Router>
|
||||
</I18nProvider>
|
||||
</KibanaContextProvider>
|
||||
|
|
|
@ -27,7 +27,7 @@ import { AnalyticsEvents } from '../analytics/constants';
|
|||
import { useAutoBottomScroll } from '../hooks/use_auto_bottom_scroll';
|
||||
import { ChatSidebar } from './chat_sidebar';
|
||||
import { useChat } from '../hooks/use_chat';
|
||||
import { ChatForm, ChatFormFields, ChatRequestData, MessageRole } from '../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields, ChatRequestData, MessageRole } from '../types';
|
||||
|
||||
import { MessageList } from './message_list/message_list';
|
||||
import { QuestionInput } from './question_input';
|
||||
|
@ -38,19 +38,19 @@ import { useUsageTracker } from '../hooks/use_usage_tracker';
|
|||
import { PlaygroundBodySection } from './playground_body_section';
|
||||
import { elasticsearchQueryString } from '../utils/user_query';
|
||||
|
||||
const buildFormData = (formData: ChatForm): ChatRequestData => ({
|
||||
connector_id: formData[ChatFormFields.summarizationModel].connectorId!,
|
||||
prompt: formData[ChatFormFields.prompt],
|
||||
indices: formData[ChatFormFields.indices].join(),
|
||||
citations: formData[ChatFormFields.citations],
|
||||
const buildFormData = (formData: PlaygroundForm): ChatRequestData => ({
|
||||
connector_id: formData[PlaygroundFormFields.summarizationModel].connectorId!,
|
||||
prompt: formData[PlaygroundFormFields.prompt],
|
||||
indices: formData[PlaygroundFormFields.indices].join(),
|
||||
citations: formData[PlaygroundFormFields.citations],
|
||||
elasticsearch_query: elasticsearchQueryString(
|
||||
formData[ChatFormFields.elasticsearchQuery],
|
||||
formData[ChatFormFields.userElasticsearchQuery],
|
||||
formData[ChatFormFields.userElasticsearchQueryValidations]
|
||||
formData[PlaygroundFormFields.elasticsearchQuery],
|
||||
formData[PlaygroundFormFields.userElasticsearchQuery],
|
||||
formData[PlaygroundFormFields.userElasticsearchQueryValidations]
|
||||
),
|
||||
summarization_model: formData[ChatFormFields.summarizationModel].value,
|
||||
source_fields: JSON.stringify(formData[ChatFormFields.sourceFields]),
|
||||
doc_size: formData[ChatFormFields.docSize],
|
||||
summarization_model: formData[PlaygroundFormFields.summarizationModel].value,
|
||||
source_fields: JSON.stringify(formData[PlaygroundFormFields.sourceFields]),
|
||||
doc_size: formData[PlaygroundFormFields.docSize],
|
||||
});
|
||||
|
||||
export const Chat = () => {
|
||||
|
@ -61,12 +61,12 @@ export const Chat = () => {
|
|||
resetField,
|
||||
handleSubmit,
|
||||
getValues,
|
||||
} = useFormContext<ChatForm>();
|
||||
} = useFormContext<PlaygroundForm>();
|
||||
const { messages, append, stop: stopRequest, setMessages, reload } = useChat();
|
||||
const messagesRef = useAutoBottomScroll();
|
||||
const [isRegenerating, setIsRegenerating] = useState<boolean>(false);
|
||||
const usageTracker = useUsageTracker();
|
||||
const onSubmit = async (data: ChatForm) => {
|
||||
const onSubmit = async (data: PlaygroundForm) => {
|
||||
await append(
|
||||
{ content: data.question, role: MessageRole.user, createdAt: new Date() },
|
||||
{
|
||||
|
@ -75,7 +75,7 @@ export const Chat = () => {
|
|||
);
|
||||
usageTracker?.click(AnalyticsEvents.chatQuestionSent);
|
||||
|
||||
resetField(ChatFormFields.question);
|
||||
resetField(PlaygroundFormFields.question);
|
||||
};
|
||||
const handleStopRequest = () => {
|
||||
stopRequest();
|
||||
|
@ -190,7 +190,7 @@ export const Chat = () => {
|
|||
<EuiSpacer size="s" />
|
||||
|
||||
<Controller
|
||||
name={ChatFormFields.question}
|
||||
name={PlaygroundFormFields.question}
|
||||
control={control}
|
||||
defaultValue=""
|
||||
rules={{
|
||||
|
|
|
@ -19,14 +19,14 @@ import { FormattedMessage } from '@kbn/i18n-react';
|
|||
import { useWatch } from 'react-hook-form';
|
||||
import { docLinks } from '../../common/doc_links';
|
||||
import { EditContextPanel } from './edit_context/edit_context_panel';
|
||||
import { ChatForm, ChatFormFields } from '../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields } from '../types';
|
||||
import { useManagementLink } from '../hooks/use_management_link';
|
||||
import { SummarizationPanel } from './summarization_panel/summarization_panel';
|
||||
|
||||
export const ChatSidebar: React.FC = () => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const selectedModel = useWatch<ChatForm, ChatFormFields.summarizationModel>({
|
||||
name: ChatFormFields.summarizationModel,
|
||||
const selectedModel = useWatch<PlaygroundForm, PlaygroundFormFields.summarizationModel>({
|
||||
name: PlaygroundFormFields.summarizationModel,
|
||||
});
|
||||
const managementLink = useManagementLink(selectedModel?.connectorId);
|
||||
const panels = [
|
||||
|
|
|
@ -9,12 +9,12 @@ import React, { useState } from 'react';
|
|||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { EuiButton } from '@elastic/eui';
|
||||
import { useWatch } from 'react-hook-form';
|
||||
import { ChatForm, ChatFormFields } from '../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields } from '../types';
|
||||
import { SelectIndicesFlyout } from './select_indices_flyout';
|
||||
|
||||
export const DataActionButton: React.FC = () => {
|
||||
const selectedIndices = useWatch<ChatForm, ChatFormFields.indices>({
|
||||
name: ChatFormFields.indices,
|
||||
const selectedIndices = useWatch<PlaygroundForm, PlaygroundFormFields.indices>({
|
||||
name: PlaygroundFormFields.indices,
|
||||
});
|
||||
const [showFlyout, setShowFlyout] = useState(false);
|
||||
const handleFlyoutClose = () => setShowFlyout(false);
|
||||
|
|
|
@ -10,7 +10,7 @@ import { render, fireEvent, screen } from '@testing-library/react';
|
|||
import { EditContextPanel } from './edit_context_panel';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import { __IntlProvider as IntlProvider } from '@kbn/i18n-react';
|
||||
import { ChatFormFields } from '../../types';
|
||||
import { PlaygroundFormFields } from '../../types';
|
||||
|
||||
jest.mock('../../hooks/use_source_indices_field', () => ({
|
||||
useSourceIndicesFields: () => ({
|
||||
|
@ -44,9 +44,9 @@ jest.mock('../../hooks/use_usage_tracker', () => ({
|
|||
const MockFormProvider = ({ children }: { children: React.ReactElement }) => {
|
||||
const methods = useForm({
|
||||
values: {
|
||||
[ChatFormFields.indices]: ['index1'],
|
||||
[ChatFormFields.docSize]: 1,
|
||||
[ChatFormFields.sourceFields]: {
|
||||
[PlaygroundFormFields.indices]: ['index1'],
|
||||
[PlaygroundFormFields.docSize]: 1,
|
||||
[PlaygroundFormFields.sourceFields]: {
|
||||
index1: ['title'],
|
||||
index2: ['body'],
|
||||
},
|
||||
|
|
|
@ -12,7 +12,7 @@ import React, { useCallback } from 'react';
|
|||
import { useController } from 'react-hook-form';
|
||||
import { useSourceIndicesFields } from '../../hooks/use_source_indices_field';
|
||||
import { useUsageTracker } from '../../hooks/use_usage_tracker';
|
||||
import { ChatForm, ChatFormFields } from '../../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields } from '../../types';
|
||||
import { AnalyticsEvents } from '../../analytics/constants';
|
||||
import { ContextFieldsSelect } from './context_fields_select';
|
||||
|
||||
|
@ -23,13 +23,13 @@ export const EditContextPanel: React.FC = () => {
|
|||
const {
|
||||
field: { onChange: onChangeSize, value: docSize },
|
||||
} = useController({
|
||||
name: ChatFormFields.docSize,
|
||||
name: PlaygroundFormFields.docSize,
|
||||
});
|
||||
|
||||
const {
|
||||
field: { onChange: onChangeSourceFields, value: sourceFields },
|
||||
} = useController<ChatForm, ChatFormFields.sourceFields>({
|
||||
name: ChatFormFields.sourceFields,
|
||||
} = useController<PlaygroundForm, PlaygroundFormFields.sourceFields>({
|
||||
name: PlaygroundFormFields.sourceFields,
|
||||
});
|
||||
|
||||
const updateSourceField = useCallback(
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
import { render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { Header } from './header';
|
||||
import { ChatFormFields, PlaygroundPageMode, PlaygroundViewMode } from '../types';
|
||||
import { PlaygroundFormFields, PlaygroundPageMode, PlaygroundViewMode } from '../types';
|
||||
import { __IntlProvider as IntlProvider } from '@kbn/i18n-react';
|
||||
import { EuiForm } from '@elastic/eui';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
|
@ -28,13 +28,13 @@ jest.mock('../hooks/use_playground_parameters', () => ({
|
|||
const MockFormProvider = ({ children }: { children: React.ReactElement }) => {
|
||||
const methods = useForm({
|
||||
values: {
|
||||
[ChatFormFields.indices]: ['index1', 'index2'],
|
||||
[ChatFormFields.queryFields]: { index1: ['field1'], index2: ['field1'] },
|
||||
[ChatFormFields.sourceFields]: {
|
||||
[PlaygroundFormFields.indices]: ['index1', 'index2'],
|
||||
[PlaygroundFormFields.queryFields]: { index1: ['field1'], index2: ['field1'] },
|
||||
[PlaygroundFormFields.sourceFields]: {
|
||||
index1: ['field1'],
|
||||
index2: ['field1'],
|
||||
},
|
||||
[ChatFormFields.elasticsearchQuery]: {
|
||||
[PlaygroundFormFields.elasticsearchQuery]: {
|
||||
retriever: {
|
||||
rrf: {
|
||||
retrievers: [
|
||||
|
@ -48,7 +48,7 @@ const MockFormProvider = ({ children }: { children: React.ReactElement }) => {
|
|||
});
|
||||
return <FormProvider {...methods}>{children}</FormProvider>;
|
||||
};
|
||||
const MockChatForm = ({
|
||||
const MockPlaygroundForm = ({
|
||||
children,
|
||||
handleSubmit,
|
||||
}: {
|
||||
|
@ -74,9 +74,9 @@ describe('Header', () => {
|
|||
});
|
||||
render(
|
||||
<IntlProvider locale="en">
|
||||
<MockChatForm handleSubmit={() => {}}>
|
||||
<MockPlaygroundForm handleSubmit={() => {}}>
|
||||
<Header onModeChange={() => {}} onSelectPageModeChange={() => {}} />
|
||||
</MockChatForm>
|
||||
</MockPlaygroundForm>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
||||
|
@ -91,9 +91,9 @@ describe('Header', () => {
|
|||
});
|
||||
render(
|
||||
<IntlProvider locale="en">
|
||||
<MockChatForm handleSubmit={() => {}}>
|
||||
<MockPlaygroundForm handleSubmit={() => {}}>
|
||||
<Header onModeChange={() => {}} onSelectPageModeChange={() => {}} />
|
||||
</MockChatForm>
|
||||
</MockPlaygroundForm>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import { FormattedMessage } from '@kbn/i18n-react';
|
|||
import { useFormContext } from 'react-hook-form';
|
||||
import { docLinks } from '../../../common/doc_links';
|
||||
import { useLLMsModels } from '../../hooks/use_llms_models';
|
||||
import { ChatForm, ChatFormFields } from '../../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields } from '../../types';
|
||||
|
||||
interface TokenEstimateTooltipProps {
|
||||
context: number;
|
||||
|
@ -37,8 +37,8 @@ export const TokenEstimateTooltip: React.FC<TokenEstimateTooltipProps> = ({
|
|||
}) => {
|
||||
const [showTooltip, setShowTooltip] = useState<boolean>(false);
|
||||
const models = useLLMsModels();
|
||||
const { getValues } = useFormContext<ChatForm>();
|
||||
const formValues = getValues(ChatFormFields.summarizationModel);
|
||||
const { getValues } = useFormContext<PlaygroundForm>();
|
||||
const formValues = getValues(PlaygroundFormFields.summarizationModel);
|
||||
|
||||
const selectedModel = models.find((m) => m.value === formValues?.value);
|
||||
|
||||
|
|
|
@ -15,7 +15,12 @@ import { SearchQueryMode } from './query_mode/search_query_mode';
|
|||
import { ChatSetupPage } from './setup_page/chat_setup_page';
|
||||
import { Header } from './header';
|
||||
import { useLoadConnectors } from '../hooks/use_load_connectors';
|
||||
import { ChatForm, ChatFormFields, PlaygroundPageMode, PlaygroundViewMode } from '../types';
|
||||
import {
|
||||
PlaygroundForm,
|
||||
PlaygroundFormFields,
|
||||
PlaygroundPageMode,
|
||||
PlaygroundViewMode,
|
||||
} from '../types';
|
||||
import { Chat } from './chat';
|
||||
import { SearchMode } from './search_mode/search_mode';
|
||||
import { SearchPlaygroundSetupPage } from './setup_page/search_playground_setup_page';
|
||||
|
@ -34,14 +39,14 @@ export interface AppProps {
|
|||
showDocs?: boolean;
|
||||
}
|
||||
|
||||
export const App: React.FC<AppProps> = ({ showDocs = false }) => {
|
||||
export const Playground: React.FC<AppProps> = ({ showDocs = false }) => {
|
||||
const isSearchModeEnabled = useSearchPlaygroundFeatureFlag();
|
||||
const { pageMode, viewMode } = usePlaygroundParameters();
|
||||
const { application } = useKibana().services;
|
||||
const { data: connectors } = useLoadConnectors();
|
||||
const hasSelectedIndices = Boolean(
|
||||
useWatch<ChatForm, ChatFormFields.indices>({
|
||||
name: ChatFormFields.indices,
|
||||
useWatch<PlaygroundForm, PlaygroundFormFields.indices>({
|
||||
name: PlaygroundFormFields.indices,
|
||||
}).length
|
||||
);
|
||||
const navigateToView = useCallback(
|
|
@ -10,7 +10,7 @@ import React from 'react';
|
|||
import { EuiFieldText } from '@elastic/eui';
|
||||
import { Controller, useFormContext } from 'react-hook-form';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { ChatFormFields } from '../../types';
|
||||
import { PlaygroundFormFields } from '../../types';
|
||||
|
||||
export const ChatPrompt = ({ isLoading }: { isLoading: boolean }) => {
|
||||
const { control } = useFormContext();
|
||||
|
@ -18,7 +18,7 @@ export const ChatPrompt = ({ isLoading }: { isLoading: boolean }) => {
|
|||
return (
|
||||
<Controller
|
||||
control={control}
|
||||
name={ChatFormFields.question}
|
||||
name={PlaygroundFormFields.question}
|
||||
render={({ field }) => (
|
||||
<EuiFieldText
|
||||
data-test-subj="searchPlaygroundChatQuestionFieldText"
|
||||
|
|
|
@ -23,10 +23,10 @@ import {
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { docLinks } from '../../../common/doc_links';
|
||||
import type { ChatForm, ChatFormFields, QuerySourceFields } from '../../types';
|
||||
import type { PlaygroundForm, PlaygroundFormFields, QuerySourceFields } from '../../types';
|
||||
|
||||
const isQueryFieldSelected = (
|
||||
queryFields: ChatForm[ChatFormFields.queryFields],
|
||||
queryFields: PlaygroundForm[PlaygroundFormFields.queryFields],
|
||||
index: string,
|
||||
field: string
|
||||
): boolean => {
|
||||
|
@ -38,7 +38,7 @@ export interface QueryFieldsPanelProps {
|
|||
index: string;
|
||||
indexFields: QuerySourceFields;
|
||||
updateFields: (index: string, fieldName: string, checked: boolean) => void;
|
||||
queryFields: ChatForm[ChatFormFields.queryFields];
|
||||
queryFields: PlaygroundForm[PlaygroundFormFields.queryFields];
|
||||
}
|
||||
|
||||
export const QueryFieldsPanel = ({
|
||||
|
|
|
@ -10,7 +10,7 @@ import { render, screen } from '@testing-library/react';
|
|||
import { QueryMode } from './query_mode';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import { __IntlProvider as IntlProvider } from '@kbn/i18n-react';
|
||||
import { ChatFormFields } from '../../types';
|
||||
import { PlaygroundFormFields } from '../../types';
|
||||
|
||||
jest.mock('../../hooks/use_source_indices_field', () => ({
|
||||
useSourceIndicesFields: () => ({
|
||||
|
@ -45,13 +45,13 @@ jest.mock('../../hooks/use_usage_tracker', () => ({
|
|||
const MockFormProvider = ({ children }: { children: React.ReactElement }) => {
|
||||
const methods = useForm({
|
||||
values: {
|
||||
[ChatFormFields.indices]: ['index1', 'index2'],
|
||||
[ChatFormFields.queryFields]: { index1: ['field1'], index2: ['field1'] },
|
||||
[ChatFormFields.sourceFields]: {
|
||||
[PlaygroundFormFields.indices]: ['index1', 'index2'],
|
||||
[PlaygroundFormFields.queryFields]: { index1: ['field1'], index2: ['field1'] },
|
||||
[PlaygroundFormFields.sourceFields]: {
|
||||
index1: ['field1'],
|
||||
index2: ['field1'],
|
||||
},
|
||||
[ChatFormFields.elasticsearchQuery]: {
|
||||
[PlaygroundFormFields.elasticsearchQuery]: {
|
||||
retriever: {
|
||||
rrf: {
|
||||
retrievers: [
|
||||
|
|
|
@ -24,7 +24,7 @@ import React, { useEffect, useMemo } from 'react';
|
|||
import { useController, useWatch } from 'react-hook-form';
|
||||
import { useSourceIndicesFields } from '../../hooks/use_source_indices_field';
|
||||
import { useUsageTracker } from '../../hooks/use_usage_tracker';
|
||||
import { ChatForm, ChatFormFields } from '../../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields } from '../../types';
|
||||
import { AnalyticsEvents } from '../../analytics/constants';
|
||||
import { docLinks } from '../../../common/doc_links';
|
||||
import { createQuery } from '../../utils/create_query';
|
||||
|
@ -32,7 +32,7 @@ import { PlaygroundBodySection } from '../playground_body_section';
|
|||
import { QueryViewSidebarContainer, QueryViewContainer } from './styles';
|
||||
|
||||
const isQueryFieldSelected = (
|
||||
queryFields: ChatForm[ChatFormFields.queryFields],
|
||||
queryFields: PlaygroundForm[PlaygroundFormFields.queryFields],
|
||||
index: string,
|
||||
field: string
|
||||
): boolean => {
|
||||
|
@ -43,18 +43,18 @@ export const QueryMode: React.FC = () => {
|
|||
const { euiTheme } = useEuiTheme();
|
||||
const usageTracker = useUsageTracker();
|
||||
const { fields } = useSourceIndicesFields();
|
||||
const sourceFields = useWatch<ChatForm, ChatFormFields.sourceFields>({
|
||||
name: ChatFormFields.sourceFields,
|
||||
const sourceFields = useWatch<PlaygroundForm, PlaygroundFormFields.sourceFields>({
|
||||
name: PlaygroundFormFields.sourceFields,
|
||||
});
|
||||
const {
|
||||
field: { onChange: queryFieldsOnChange, value: queryFields },
|
||||
} = useController<ChatForm, ChatFormFields.queryFields>({
|
||||
name: ChatFormFields.queryFields,
|
||||
} = useController<PlaygroundForm, PlaygroundFormFields.queryFields>({
|
||||
name: PlaygroundFormFields.queryFields,
|
||||
});
|
||||
const {
|
||||
field: { onChange: elasticsearchQueryChange, value: elasticsearchQuery },
|
||||
} = useController<ChatForm, ChatFormFields.elasticsearchQuery>({
|
||||
name: ChatFormFields.elasticsearchQuery,
|
||||
} = useController<PlaygroundForm, PlaygroundFormFields.elasticsearchQuery>({
|
||||
name: PlaygroundFormFields.elasticsearchQuery,
|
||||
});
|
||||
|
||||
const updateFields = (index: string, fieldName: string, checked: boolean) => {
|
||||
|
|
|
@ -12,7 +12,7 @@ import { FormattedMessage } from '@kbn/i18n-react';
|
|||
import { useController, useWatch } from 'react-hook-form';
|
||||
import { useSourceIndicesFields } from '../../hooks/use_source_indices_field';
|
||||
import { useUsageTracker } from '../../hooks/use_usage_tracker';
|
||||
import { ChatForm, ChatFormFields, PlaygroundPageMode } from '../../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields, PlaygroundPageMode } from '../../types';
|
||||
import { AnalyticsEvents } from '../../analytics/constants';
|
||||
import { createQuery } from '../../utils/create_query';
|
||||
import { SearchQuery } from './search_query';
|
||||
|
@ -35,28 +35,28 @@ export const QuerySidePanel = ({
|
|||
}: QuerySidePanelProps) => {
|
||||
const usageTracker = useUsageTracker();
|
||||
const { fields } = useSourceIndicesFields();
|
||||
const sourceFields = useWatch<ChatForm, ChatFormFields.sourceFields>({
|
||||
name: ChatFormFields.sourceFields,
|
||||
const sourceFields = useWatch<PlaygroundForm, PlaygroundFormFields.sourceFields>({
|
||||
name: PlaygroundFormFields.sourceFields,
|
||||
});
|
||||
const {
|
||||
field: { onChange: queryFieldsOnChange, value: queryFields },
|
||||
} = useController<ChatForm, ChatFormFields.queryFields>({
|
||||
name: ChatFormFields.queryFields,
|
||||
} = useController<PlaygroundForm, PlaygroundFormFields.queryFields>({
|
||||
name: PlaygroundFormFields.queryFields,
|
||||
});
|
||||
const {
|
||||
field: { onChange: elasticsearchQueryChange },
|
||||
} = useController<ChatForm, ChatFormFields.elasticsearchQuery>({
|
||||
name: ChatFormFields.elasticsearchQuery,
|
||||
} = useController<PlaygroundForm, PlaygroundFormFields.elasticsearchQuery>({
|
||||
name: PlaygroundFormFields.elasticsearchQuery,
|
||||
});
|
||||
const {
|
||||
field: { onChange: userElasticsearchQueryChange },
|
||||
} = useController<ChatForm, ChatFormFields.userElasticsearchQuery>({
|
||||
name: ChatFormFields.userElasticsearchQuery,
|
||||
} = useController<PlaygroundForm, PlaygroundFormFields.userElasticsearchQuery>({
|
||||
name: PlaygroundFormFields.userElasticsearchQuery,
|
||||
});
|
||||
const {
|
||||
field: { value: userElasticsearchQueryValidations },
|
||||
} = useController<ChatForm, ChatFormFields.userElasticsearchQueryValidations>({
|
||||
name: ChatFormFields.userElasticsearchQueryValidations,
|
||||
} = useController<PlaygroundForm, PlaygroundFormFields.userElasticsearchQueryValidations>({
|
||||
name: PlaygroundFormFields.userElasticsearchQueryValidations,
|
||||
});
|
||||
|
||||
const handleSearch = useCallback(
|
||||
|
|
|
@ -23,7 +23,7 @@ import { CodeEditor } from '@kbn/code-editor';
|
|||
import { monaco as monacoEditor } from '@kbn/monaco';
|
||||
|
||||
import { Controller, useController, useFormContext } from 'react-hook-form';
|
||||
import { ChatForm, ChatFormFields } from '../../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields } from '../../types';
|
||||
import { FullHeight, QueryViewTitlePanel, PanelFillContainer } from './styles';
|
||||
import { formatElasticsearchQueryString } from '../../utils/user_query';
|
||||
|
||||
|
@ -37,21 +37,21 @@ export const ElasticsearchQueryViewer = ({
|
|||
isLoading: boolean;
|
||||
}) => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const { control } = useFormContext<ChatForm>();
|
||||
const { control } = useFormContext<PlaygroundForm>();
|
||||
const {
|
||||
field: { value: elasticsearchQuery },
|
||||
} = useController<ChatForm, ChatFormFields.elasticsearchQuery>({
|
||||
name: ChatFormFields.elasticsearchQuery,
|
||||
} = useController<PlaygroundForm, PlaygroundFormFields.elasticsearchQuery>({
|
||||
name: PlaygroundFormFields.elasticsearchQuery,
|
||||
});
|
||||
const {
|
||||
field: { value: userElasticsearchQuery, onChange: onChangeUserQuery },
|
||||
} = useController<ChatForm, ChatFormFields.userElasticsearchQuery>({
|
||||
name: ChatFormFields.userElasticsearchQuery,
|
||||
} = useController<PlaygroundForm, PlaygroundFormFields.userElasticsearchQuery>({
|
||||
name: PlaygroundFormFields.userElasticsearchQuery,
|
||||
});
|
||||
const {
|
||||
field: { value: userElasticsearchQueryValidations },
|
||||
} = useController<ChatForm, ChatFormFields.userElasticsearchQueryValidations>({
|
||||
name: ChatFormFields.userElasticsearchQueryValidations,
|
||||
} = useController<PlaygroundForm, PlaygroundFormFields.userElasticsearchQueryValidations>({
|
||||
name: PlaygroundFormFields.userElasticsearchQueryValidations,
|
||||
});
|
||||
const generatedEsQuery = useMemo(
|
||||
() => formatElasticsearchQueryString(elasticsearchQuery),
|
||||
|
@ -154,7 +154,7 @@ export const ElasticsearchQueryViewer = ({
|
|||
<EuiSplitPanel.Inner paddingSize="none" css={PanelFillContainer}>
|
||||
<Controller
|
||||
control={control}
|
||||
name={ChatFormFields.userElasticsearchQuery}
|
||||
name={PlaygroundFormFields.userElasticsearchQuery}
|
||||
render={({ field }) => (
|
||||
<CodeEditor
|
||||
dataTestSubj="ViewElasticsearchQueryResult"
|
||||
|
|
|
@ -10,21 +10,21 @@ import React from 'react';
|
|||
import { EuiFieldText } from '@elastic/eui';
|
||||
import { Controller, useController, useFormContext } from 'react-hook-form';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { ChatForm, ChatFormFields } from '../../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields } from '../../types';
|
||||
|
||||
export const SearchQuery = ({ isLoading }: { isLoading: boolean }) => {
|
||||
const { control } = useFormContext();
|
||||
const {
|
||||
field: { value: searchBarValue },
|
||||
formState: { isSubmitting },
|
||||
} = useController<ChatForm, ChatFormFields.searchQuery>({
|
||||
name: ChatFormFields.searchQuery,
|
||||
} = useController<PlaygroundForm, PlaygroundFormFields.searchQuery>({
|
||||
name: PlaygroundFormFields.searchQuery,
|
||||
});
|
||||
|
||||
return (
|
||||
<Controller
|
||||
control={control}
|
||||
name={ChatFormFields.searchQuery}
|
||||
name={PlaygroundFormFields.searchQuery}
|
||||
render={({ field }) => (
|
||||
<EuiFieldText
|
||||
data-test-subj="searchPlaygroundSearchModeFieldText"
|
||||
|
|
|
@ -22,7 +22,7 @@ import { ElasticsearchQueryViewer } from './query_viewer';
|
|||
import { ElasticsearchQueryOutput } from './query_output';
|
||||
import { QuerySidePanel } from './query_side_panel';
|
||||
import { useElasticsearchQuery } from '../../hooks/use_elasticsearch_query';
|
||||
import { ChatForm, ChatFormFields, PlaygroundPageMode } from '../../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields, PlaygroundPageMode } from '../../types';
|
||||
import {
|
||||
FullHeight,
|
||||
QueryViewContainer,
|
||||
|
@ -40,18 +40,18 @@ export const SearchQueryMode = ({ pageMode }: { pageMode: PlaygroundPageMode })
|
|||
const { executeQuery, data, error, isError, fetchStatus } = useElasticsearchQuery(pageMode);
|
||||
const {
|
||||
field: { value: searchQuery },
|
||||
} = useController<ChatForm, ChatFormFields.searchQuery>({
|
||||
name: ChatFormFields.searchQuery,
|
||||
} = useController<PlaygroundForm, PlaygroundFormFields.searchQuery>({
|
||||
name: PlaygroundFormFields.searchQuery,
|
||||
});
|
||||
const {
|
||||
field: { value: question },
|
||||
} = useController<ChatForm, ChatFormFields.question>({
|
||||
name: ChatFormFields.question,
|
||||
} = useController<PlaygroundForm, PlaygroundFormFields.question>({
|
||||
name: PlaygroundFormFields.question,
|
||||
});
|
||||
const {
|
||||
field: { value: userElasticsearchQueryValidations },
|
||||
} = useController<ChatForm, ChatFormFields.userElasticsearchQueryValidations>({
|
||||
name: ChatFormFields.userElasticsearchQueryValidations,
|
||||
} = useController<PlaygroundForm, PlaygroundFormFields.userElasticsearchQueryValidations>({
|
||||
name: PlaygroundFormFields.userElasticsearchQueryValidations,
|
||||
});
|
||||
const executeQueryDisabled = disableExecuteQuery(
|
||||
userElasticsearchQueryValidations,
|
||||
|
|
|
@ -12,14 +12,14 @@ import { __IntlProvider as IntlProvider } from '@kbn/i18n-react';
|
|||
import { QuestionInput } from './question_input';
|
||||
|
||||
const mockButton = (
|
||||
<EuiButton data-test="btn" className="btn" onClick={() => {}}>
|
||||
<EuiButton data-test-subj="btn" className="btn" onClick={() => {}}>
|
||||
Send
|
||||
</EuiButton>
|
||||
);
|
||||
|
||||
const handleOnSubmitMock = jest.fn();
|
||||
|
||||
const MockChatForm = ({
|
||||
const MockPlaygroundForm = ({
|
||||
children,
|
||||
handleSubmit,
|
||||
}: {
|
||||
|
@ -40,9 +40,9 @@ describe('Question Input', () => {
|
|||
it('correctly', () => {
|
||||
render(
|
||||
<IntlProvider locale="en">
|
||||
<MockChatForm handleSubmit={handleOnSubmitMock}>
|
||||
<MockPlaygroundForm handleSubmit={handleOnSubmitMock}>
|
||||
<QuestionInput value="" onChange={() => {}} button={mockButton} isDisabled={false} />
|
||||
</MockChatForm>
|
||||
</MockPlaygroundForm>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
||||
|
@ -52,14 +52,14 @@ describe('Question Input', () => {
|
|||
it('disabled', () => {
|
||||
render(
|
||||
<IntlProvider locale="en">
|
||||
<MockChatForm handleSubmit={handleOnSubmitMock}>
|
||||
<MockPlaygroundForm handleSubmit={handleOnSubmitMock}>
|
||||
<QuestionInput
|
||||
value="my question"
|
||||
onChange={() => {}}
|
||||
button={mockButton}
|
||||
isDisabled={true}
|
||||
/>
|
||||
</MockChatForm>
|
||||
</MockPlaygroundForm>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
||||
|
@ -69,14 +69,14 @@ describe('Question Input', () => {
|
|||
it('with value', () => {
|
||||
render(
|
||||
<IntlProvider locale="en">
|
||||
<MockChatForm handleSubmit={handleOnSubmitMock}>
|
||||
<MockPlaygroundForm handleSubmit={handleOnSubmitMock}>
|
||||
<QuestionInput
|
||||
value="my question"
|
||||
onChange={() => {}}
|
||||
button={mockButton}
|
||||
isDisabled={false}
|
||||
/>
|
||||
</MockChatForm>
|
||||
</MockPlaygroundForm>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
||||
|
@ -86,9 +86,9 @@ describe('Question Input', () => {
|
|||
it('submits form', () => {
|
||||
render(
|
||||
<IntlProvider locale="en">
|
||||
<MockChatForm handleSubmit={handleOnSubmitMock}>
|
||||
<MockPlaygroundForm handleSubmit={handleOnSubmitMock}>
|
||||
<QuestionInput value="" onChange={() => {}} button={mockButton} isDisabled={false} />
|
||||
</MockChatForm>
|
||||
</MockPlaygroundForm>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
||||
|
|
|
@ -20,19 +20,19 @@ import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
|
|||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { DEFAULT_PAGINATION } from '../../../common';
|
||||
import { ResultList } from './result_list';
|
||||
import { ChatForm, ChatFormFields, Pagination } from '../../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields, Pagination } from '../../types';
|
||||
import { useSearchPreview } from '../../hooks/use_search_preview';
|
||||
import { getPaginationFromPage } from '../../utils/pagination_helper';
|
||||
import { useIndexMappings } from '../../hooks/use_index_mappings';
|
||||
|
||||
export const SearchMode: React.FC = () => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const { control } = useFormContext<ChatForm>();
|
||||
const { control } = useFormContext<PlaygroundForm>();
|
||||
const {
|
||||
field: { value: searchBarValue },
|
||||
formState: { isSubmitting },
|
||||
} = useController<ChatForm, ChatFormFields.searchQuery>({
|
||||
name: ChatFormFields.searchQuery,
|
||||
} = useController<PlaygroundForm, PlaygroundFormFields.searchQuery>({
|
||||
name: PlaygroundFormFields.searchQuery,
|
||||
});
|
||||
|
||||
const [searchQuery, setSearchQuery] = React.useState<{
|
||||
|
@ -76,7 +76,7 @@ export const SearchMode: React.FC = () => {
|
|||
<EuiFlexItem grow={false}>
|
||||
<Controller
|
||||
control={control}
|
||||
name={ChatFormFields.searchQuery}
|
||||
name={PlaygroundFormFields.searchQuery}
|
||||
render={({ field }) => (
|
||||
<EuiFieldSearch
|
||||
data-test-subj="searchPlaygroundSearchModeFieldText"
|
||||
|
|
|
@ -9,13 +9,13 @@ import React, { useState } from 'react';
|
|||
import { useFormContext } from 'react-hook-form';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { EuiButton, EuiButtonEmpty } from '@elastic/eui';
|
||||
import { ChatForm, ChatFormFields } from '../../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields } from '../../types';
|
||||
import { SelectIndicesFlyout } from '../select_indices_flyout';
|
||||
|
||||
export const AddDataSources: React.FC = () => {
|
||||
const [showFlyout, setShowFlyout] = useState(false);
|
||||
const { getValues } = useFormContext<ChatForm>();
|
||||
const hasSelectedIndices: boolean = !!getValues(ChatFormFields.indices)?.length;
|
||||
const { getValues } = useFormContext<PlaygroundForm>();
|
||||
const hasSelectedIndices: boolean = !!getValues(PlaygroundFormFields.indices)?.length;
|
||||
const handleFlyoutClose = () => {
|
||||
setShowFlyout(false);
|
||||
};
|
||||
|
|
|
@ -12,17 +12,17 @@ import { EuiPanel } from '@elastic/eui';
|
|||
import { useLLMsModels } from '../../hooks/use_llms_models';
|
||||
import { IncludeCitationsField } from './include_citations_field';
|
||||
import { InstructionsField } from './instructions_field';
|
||||
import { ChatForm, ChatFormFields } from '../../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields } from '../../types';
|
||||
import { SummarizationModel } from './summarization_model';
|
||||
|
||||
export const SummarizationPanel: React.FC = () => {
|
||||
const { control } = useFormContext<ChatForm>();
|
||||
const { control } = useFormContext<PlaygroundForm>();
|
||||
const models = useLLMsModels();
|
||||
|
||||
return (
|
||||
<EuiPanel data-test-subj="summarizationPanel">
|
||||
<Controller
|
||||
name={ChatFormFields.summarizationModel}
|
||||
name={PlaygroundFormFields.summarizationModel}
|
||||
rules={{ required: true }}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
|
@ -35,7 +35,7 @@ export const SummarizationPanel: React.FC = () => {
|
|||
/>
|
||||
|
||||
<Controller
|
||||
name={ChatFormFields.prompt}
|
||||
name={PlaygroundFormFields.prompt}
|
||||
control={control}
|
||||
rules={{ required: true }}
|
||||
defaultValue="You are an assistant for question-answering tasks."
|
||||
|
@ -43,7 +43,7 @@ export const SummarizationPanel: React.FC = () => {
|
|||
/>
|
||||
|
||||
<Controller
|
||||
name={ChatFormFields.citations}
|
||||
name={PlaygroundFormFields.citations}
|
||||
control={control}
|
||||
defaultValue={true}
|
||||
render={({ field }) => (
|
||||
|
|
|
@ -9,17 +9,17 @@ import React from 'react';
|
|||
|
||||
import { EuiCodeBlock } from '@elastic/eui';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { ChatForm, ChatFormFields } from '../../../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields } from '../../../types';
|
||||
import { elasticsearchQueryObject } from '../../../utils/user_query';
|
||||
|
||||
export const DevToolsCode: React.FC = () => {
|
||||
const { getValues } = useFormContext<ChatForm>();
|
||||
const { getValues } = useFormContext<PlaygroundForm>();
|
||||
const {
|
||||
[ChatFormFields.indices]: indices,
|
||||
[ChatFormFields.elasticsearchQuery]: esQuery,
|
||||
[ChatFormFields.searchQuery]: searchQuery,
|
||||
[ChatFormFields.userElasticsearchQuery]: userElasticsearchQuery,
|
||||
[ChatFormFields.userElasticsearchQueryValidations]: userElasticsearchQueryValidations,
|
||||
[PlaygroundFormFields.indices]: indices,
|
||||
[PlaygroundFormFields.elasticsearchQuery]: esQuery,
|
||||
[PlaygroundFormFields.searchQuery]: searchQuery,
|
||||
[PlaygroundFormFields.userElasticsearchQuery]: userElasticsearchQuery,
|
||||
[PlaygroundFormFields.userElasticsearchQueryValidations]: userElasticsearchQueryValidations,
|
||||
} = getValues();
|
||||
const query = elasticsearchQueryObject(
|
||||
esQuery,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { render } from '@testing-library/react';
|
||||
import { PY_LANG_CLIENT } from './py_lang_client'; // Adjust the import path according to your project structure
|
||||
import { ES_CLIENT_DETAILS } from '../view_code_flyout';
|
||||
import { ChatForm } from '../../../types';
|
||||
import { PlaygroundForm } from '../../../types';
|
||||
|
||||
describe('PY_LANG_CLIENT function', () => {
|
||||
test('renders with correct content', () => {
|
||||
|
@ -21,7 +21,7 @@ describe('PY_LANG_CLIENT function', () => {
|
|||
prompt: 'Your prompt',
|
||||
citations: true,
|
||||
summarization_model: 'Your-new-model',
|
||||
} as unknown as ChatForm;
|
||||
} as unknown as PlaygroundForm;
|
||||
|
||||
const clientDetails = ES_CLIENT_DETAILS('http://my-local-cloud-instance');
|
||||
|
||||
|
@ -39,7 +39,7 @@ describe('PY_LANG_CLIENT function', () => {
|
|||
prompt: 'Your prompt',
|
||||
citations: true,
|
||||
summarization_model: 'Your-new-model',
|
||||
} as unknown as ChatForm;
|
||||
} as unknown as PlaygroundForm;
|
||||
|
||||
const clientDetails = ES_CLIENT_DETAILS('http://my-local-cloud-instance');
|
||||
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
|
||||
import { EuiCodeBlock } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { ChatForm } from '../../../types';
|
||||
import { PlaygroundForm } from '../../../types';
|
||||
import { Prompt } from '../../../../common/prompt';
|
||||
import { elasticsearchQueryObject } from '../../../utils/user_query';
|
||||
import { getESQuery } from './utils';
|
||||
|
||||
export const PY_LANG_CLIENT = (formValues: ChatForm, clientDetails: string) => (
|
||||
export const PY_LANG_CLIENT = (formValues: PlaygroundForm, clientDetails: string) => (
|
||||
<EuiCodeBlock language="py" isCopyable overflowHeight="100%">
|
||||
{`## Install the required packages
|
||||
## pip install -qU elasticsearch openai
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { ES_CLIENT_DETAILS } from '../view_code_flyout';
|
||||
import { ChatForm } from '../../../types';
|
||||
import { PlaygroundForm } from '../../../types';
|
||||
import { LangchainPythonExmaple } from './py_langchain_python';
|
||||
|
||||
describe('LangchainPythonExmaple component', () => {
|
||||
|
@ -21,7 +21,7 @@ describe('LangchainPythonExmaple component', () => {
|
|||
prompt: 'Your prompt',
|
||||
citations: true,
|
||||
summarization_model: 'Your-new-model',
|
||||
} as unknown as ChatForm;
|
||||
} as unknown as PlaygroundForm;
|
||||
|
||||
const clientDetails = ES_CLIENT_DETAILS('http://my-local-cloud-instance');
|
||||
|
||||
|
@ -42,7 +42,7 @@ describe('LangchainPythonExmaple component', () => {
|
|||
prompt: 'Your prompt',
|
||||
citations: true,
|
||||
summarization_model: 'Your-new-model',
|
||||
} as unknown as ChatForm;
|
||||
} as unknown as PlaygroundForm;
|
||||
|
||||
const clientDetails = ES_CLIENT_DETAILS('http://my-local-cloud-instance');
|
||||
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
|
||||
import { EuiCodeBlock } from '@elastic/eui';
|
||||
import React, { useMemo } from 'react';
|
||||
import { ChatForm } from '../../../types';
|
||||
import { PlaygroundForm } from '../../../types';
|
||||
import { Prompt } from '../../../../common/prompt';
|
||||
import { elasticsearchQueryObject } from '../../../utils/user_query';
|
||||
import { getESQuery } from './utils';
|
||||
|
||||
export const getSourceFields = (sourceFields: ChatForm['source_fields']) => {
|
||||
export const getSourceFields = (sourceFields: PlaygroundForm['source_fields']) => {
|
||||
let hasContentFieldsArray = false;
|
||||
const fields: Record<string, string | string[]> = {};
|
||||
for (const indexName of Object.keys(sourceFields)) {
|
||||
|
@ -33,7 +33,7 @@ export const LangchainPythonExmaple = ({
|
|||
formValues,
|
||||
clientDetails,
|
||||
}: {
|
||||
formValues: ChatForm;
|
||||
formValues: PlaygroundForm;
|
||||
clientDetails: string;
|
||||
}) => {
|
||||
const { esQuery, hasContentFieldsArray, indices, prompt, sourceFields } = useMemo(() => {
|
||||
|
|
|
@ -9,15 +9,15 @@ import React, { useState } from 'react';
|
|||
import { EuiButton } from '@elastic/eui';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { ChatForm, ChatFormFields, PlaygroundPageMode } from '../../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields, PlaygroundPageMode } from '../../types';
|
||||
import { ViewCodeFlyout } from './view_code_flyout';
|
||||
|
||||
export const ViewCodeAction: React.FC<{ selectedPageMode: PlaygroundPageMode }> = ({
|
||||
selectedPageMode = PlaygroundPageMode.chat,
|
||||
}) => {
|
||||
const { watch } = useFormContext<ChatForm>();
|
||||
const { watch } = useFormContext<PlaygroundForm>();
|
||||
const [showFlyout, setShowFlyout] = useState(false);
|
||||
const selectedIndices = watch(ChatFormFields.indices);
|
||||
const selectedIndices = watch(PlaygroundFormFields.indices);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -22,7 +22,7 @@ import React, { useEffect, useState } from 'react';
|
|||
import { useFormContext } from 'react-hook-form';
|
||||
import { AnalyticsEvents } from '../../analytics/constants';
|
||||
import { useUsageTracker } from '../../hooks/use_usage_tracker';
|
||||
import { ChatForm, PlaygroundPageMode } from '../../types';
|
||||
import { PlaygroundForm, PlaygroundPageMode } from '../../types';
|
||||
import { useKibana } from '../../hooks/use_kibana';
|
||||
import { MANAGEMENT_API_KEYS } from '../../../common/routes';
|
||||
import { LangchainPythonExmaple } from './examples/py_langchain_python';
|
||||
|
@ -46,7 +46,7 @@ es_client = Elasticsearch(
|
|||
export const ViewCodeFlyout: React.FC<ViewCodeFlyoutProps> = ({ onClose, selectedPageMode }) => {
|
||||
const usageTracker = useUsageTracker();
|
||||
const [selectedLanguage, setSelectedLanguage] = useState('py-es-client');
|
||||
const { getValues } = useFormContext<ChatForm>();
|
||||
const { getValues } = useFormContext<PlaygroundForm>();
|
||||
const formValues = getValues();
|
||||
const {
|
||||
services: { cloud, http },
|
||||
|
@ -103,6 +103,7 @@ export const ViewCodeFlyout: React.FC<ViewCodeFlyoutProps> = ({ onClose, selecte
|
|||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiSelect
|
||||
data-test-subj="view-code-lang-select"
|
||||
options={[
|
||||
{ value: 'py-es-client', text: 'Python Elasticsearch Client with OpenAI' },
|
||||
{ value: 'lc-py', text: 'LangChain Python with OpenAI' },
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { useMutation } from '@tanstack/react-query';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { useKibana } from './use_kibana';
|
||||
import { APIRoutes, ChatFormFields } from '../types';
|
||||
import { APIRoutes, PlaygroundFormFields } from '../types';
|
||||
|
||||
interface UseApiKeyQueryParams {
|
||||
name: string;
|
||||
|
@ -27,7 +27,7 @@ export const useCreateApiKeyQuery = () => {
|
|||
body: JSON.stringify({
|
||||
name,
|
||||
expiresInDays,
|
||||
indices: getValues(ChatFormFields.indices),
|
||||
indices: getValues(PlaygroundFormFields.indices),
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ import { useQuery } from '@tanstack/react-query';
|
|||
import { useFormContext } from 'react-hook-form';
|
||||
import {
|
||||
APIRoutes,
|
||||
ChatForm,
|
||||
ChatFormFields,
|
||||
PlaygroundForm,
|
||||
PlaygroundFormFields,
|
||||
PlaygroundPageMode,
|
||||
QueryTestResponse,
|
||||
} from '../types';
|
||||
|
@ -19,29 +19,29 @@ import { elasticsearchQueryString } from '../utils/user_query';
|
|||
|
||||
export const useElasticsearchQuery = (pageMode: PlaygroundPageMode) => {
|
||||
const { http } = useKibana().services;
|
||||
const { getValues } = useFormContext<ChatForm>();
|
||||
const { getValues } = useFormContext<PlaygroundForm>();
|
||||
const executeEsQuery = () => {
|
||||
const formValues = getValues();
|
||||
const esQuery = elasticsearchQueryString(
|
||||
formValues[ChatFormFields.elasticsearchQuery],
|
||||
formValues[ChatFormFields.userElasticsearchQuery],
|
||||
formValues[ChatFormFields.userElasticsearchQueryValidations]
|
||||
formValues[PlaygroundFormFields.elasticsearchQuery],
|
||||
formValues[PlaygroundFormFields.userElasticsearchQuery],
|
||||
formValues[PlaygroundFormFields.userElasticsearchQueryValidations]
|
||||
);
|
||||
const body =
|
||||
pageMode === PlaygroundPageMode.chat
|
||||
? JSON.stringify({
|
||||
elasticsearch_query: esQuery,
|
||||
indices: formValues[ChatFormFields.indices],
|
||||
query: formValues[ChatFormFields.question],
|
||||
indices: formValues[PlaygroundFormFields.indices],
|
||||
query: formValues[PlaygroundFormFields.question],
|
||||
chat_context: {
|
||||
source_fields: JSON.stringify(formValues[ChatFormFields.sourceFields]),
|
||||
doc_size: formValues[ChatFormFields.docSize],
|
||||
source_fields: JSON.stringify(formValues[PlaygroundFormFields.sourceFields]),
|
||||
doc_size: formValues[PlaygroundFormFields.docSize],
|
||||
},
|
||||
})
|
||||
: JSON.stringify({
|
||||
elasticsearch_query: esQuery,
|
||||
indices: formValues[ChatFormFields.indices],
|
||||
query: formValues[ChatFormFields.searchQuery],
|
||||
indices: formValues[PlaygroundFormFields.indices],
|
||||
query: formValues[PlaygroundFormFields.searchQuery],
|
||||
});
|
||||
|
||||
return http.post<QueryTestResponse>(APIRoutes.POST_QUERY_TEST, {
|
||||
|
|
|
@ -9,11 +9,11 @@ import { useQuery } from '@tanstack/react-query';
|
|||
import type { HttpSetup } from '@kbn/core-http-browser';
|
||||
import { IndicesGetMappingResponse } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { APIRoutes, ChatForm, ChatFormFields } from '../types';
|
||||
import { APIRoutes, PlaygroundForm, PlaygroundFormFields } from '../types';
|
||||
import { useKibana } from './use_kibana';
|
||||
|
||||
export interface FetchIndexMappingsArgs {
|
||||
indices: ChatForm[ChatFormFields.indices];
|
||||
indices: PlaygroundForm[PlaygroundFormFields.indices];
|
||||
http: HttpSetup;
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ export const useIndexMappings = () => {
|
|||
services: { http },
|
||||
} = useKibana();
|
||||
const { getValues } = useFormContext();
|
||||
const indices = getValues(ChatFormFields.indices);
|
||||
const indices = getValues(PlaygroundFormFields.indices);
|
||||
const { data } = useQuery({
|
||||
queryKey: ['search-playground-index-mappings'],
|
||||
queryFn: () => fetchIndexMappings({ indices, http }),
|
||||
|
|
|
@ -11,7 +11,7 @@ import { useUsageTracker } from './use_usage_tracker';
|
|||
import { useIndicesFields } from './use_indices_fields';
|
||||
import { createQuery, getDefaultQueryFields, getDefaultSourceFields } from '../utils/create_query';
|
||||
import { AnalyticsEvents } from '../analytics/constants';
|
||||
import { ChatFormFields } from '../types';
|
||||
import { PlaygroundFormFields } from '../types';
|
||||
|
||||
// Mock dependencies
|
||||
jest.mock('./use_usage_tracker');
|
||||
|
@ -49,18 +49,21 @@ describe('useLoadFieldsByIndices', () => {
|
|||
isFetched: true,
|
||||
});
|
||||
mockGetValues.mockReturnValueOnce({
|
||||
[ChatFormFields.queryFields]: {},
|
||||
[ChatFormFields.sourceFields]: {},
|
||||
[PlaygroundFormFields.queryFields]: {},
|
||||
[PlaygroundFormFields.sourceFields]: {},
|
||||
});
|
||||
mockWatch.mockReturnValue(['index1']);
|
||||
|
||||
setup();
|
||||
|
||||
expect(mockSetValue).toHaveBeenCalledWith(ChatFormFields.elasticsearchQuery, 'mocked query');
|
||||
expect(mockSetValue).toHaveBeenCalledWith(ChatFormFields.queryFields, {
|
||||
expect(mockSetValue).toHaveBeenCalledWith(
|
||||
PlaygroundFormFields.elasticsearchQuery,
|
||||
'mocked query'
|
||||
);
|
||||
expect(mockSetValue).toHaveBeenCalledWith(PlaygroundFormFields.queryFields, {
|
||||
newIndex: ['title', 'body'],
|
||||
});
|
||||
expect(mockSetValue).toHaveBeenCalledWith(ChatFormFields.sourceFields, {
|
||||
expect(mockSetValue).toHaveBeenCalledWith(PlaygroundFormFields.sourceFields, {
|
||||
testIndex: ['content'],
|
||||
});
|
||||
expect(mockUsageTracker.count).toHaveBeenCalledWith(AnalyticsEvents.sourceFieldsLoaded, 2);
|
||||
|
@ -71,17 +74,17 @@ describe('useLoadFieldsByIndices', () => {
|
|||
(getDefaultQueryFields as jest.Mock).mockReturnValue({ index: ['title', 'body'] });
|
||||
(getDefaultSourceFields as jest.Mock).mockReturnValue({ index: ['title'] });
|
||||
mockGetValues.mockReturnValueOnce({
|
||||
[ChatFormFields.queryFields]: { index: [] },
|
||||
[ChatFormFields.sourceFields]: { index: ['body'] },
|
||||
[PlaygroundFormFields.queryFields]: { index: [] },
|
||||
[PlaygroundFormFields.sourceFields]: { index: ['body'] },
|
||||
});
|
||||
|
||||
setup();
|
||||
|
||||
expect(mockSetValue).toHaveBeenCalledTimes(3);
|
||||
expect(mockSetValue).toHaveBeenNthCalledWith(2, ChatFormFields.queryFields, {
|
||||
expect(mockSetValue).toHaveBeenNthCalledWith(2, PlaygroundFormFields.queryFields, {
|
||||
index: [],
|
||||
});
|
||||
expect(mockSetValue).toHaveBeenNthCalledWith(3, ChatFormFields.sourceFields, {
|
||||
expect(mockSetValue).toHaveBeenNthCalledWith(3, PlaygroundFormFields.sourceFields, {
|
||||
index: ['body'],
|
||||
});
|
||||
});
|
||||
|
@ -90,16 +93,16 @@ describe('useLoadFieldsByIndices', () => {
|
|||
(getDefaultQueryFields as jest.Mock).mockReturnValue({ index: ['title', 'body'] });
|
||||
(getDefaultSourceFields as jest.Mock).mockReturnValue({ index: ['title'] });
|
||||
mockGetValues.mockReturnValueOnce({
|
||||
[ChatFormFields.queryFields]: { index: [], oldIndex: ['title'] },
|
||||
[ChatFormFields.sourceFields]: { index: ['body'], oldIndex: ['title'] },
|
||||
[PlaygroundFormFields.queryFields]: { index: [], oldIndex: ['title'] },
|
||||
[PlaygroundFormFields.sourceFields]: { index: ['body'], oldIndex: ['title'] },
|
||||
});
|
||||
|
||||
setup();
|
||||
|
||||
expect(mockSetValue).toHaveBeenNthCalledWith(2, ChatFormFields.queryFields, {
|
||||
expect(mockSetValue).toHaveBeenNthCalledWith(2, PlaygroundFormFields.queryFields, {
|
||||
index: [],
|
||||
});
|
||||
expect(mockSetValue).toHaveBeenNthCalledWith(3, ChatFormFields.sourceFields, {
|
||||
expect(mockSetValue).toHaveBeenNthCalledWith(3, PlaygroundFormFields.sourceFields, {
|
||||
index: ['body'],
|
||||
});
|
||||
});
|
||||
|
@ -114,17 +117,17 @@ describe('useLoadFieldsByIndices', () => {
|
|||
newIndex: ['content'],
|
||||
});
|
||||
mockGetValues.mockReturnValueOnce({
|
||||
[ChatFormFields.queryFields]: { index: [], oldIndex: ['title'] },
|
||||
[ChatFormFields.sourceFields]: { index: ['body'], oldIndex: ['title'] },
|
||||
[PlaygroundFormFields.queryFields]: { index: [], oldIndex: ['title'] },
|
||||
[PlaygroundFormFields.sourceFields]: { index: ['body'], oldIndex: ['title'] },
|
||||
});
|
||||
|
||||
setup();
|
||||
|
||||
expect(mockSetValue).toHaveBeenNthCalledWith(2, ChatFormFields.queryFields, {
|
||||
expect(mockSetValue).toHaveBeenNthCalledWith(2, PlaygroundFormFields.queryFields, {
|
||||
index: [],
|
||||
newIndex: ['content'],
|
||||
});
|
||||
expect(mockSetValue).toHaveBeenNthCalledWith(3, ChatFormFields.sourceFields, {
|
||||
expect(mockSetValue).toHaveBeenNthCalledWith(3, PlaygroundFormFields.sourceFields, {
|
||||
index: ['body'],
|
||||
newIndex: ['content'],
|
||||
});
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { useEffect } from 'react';
|
||||
import { UseFormReturn } from 'react-hook-form/dist/types';
|
||||
import { useUsageTracker } from './use_usage_tracker';
|
||||
import { ChatForm, ChatFormFields } from '../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields } from '../types';
|
||||
import { useIndicesFields } from './use_indices_fields';
|
||||
import {
|
||||
createQuery,
|
||||
|
@ -32,17 +32,17 @@ export const useLoadFieldsByIndices = ({
|
|||
watch,
|
||||
setValue,
|
||||
getValues,
|
||||
}: Pick<UseFormReturn<ChatForm>, 'watch' | 'getValues' | 'setValue'>) => {
|
||||
}: Pick<UseFormReturn<PlaygroundForm>, 'watch' | 'getValues' | 'setValue'>) => {
|
||||
const usageTracker = useUsageTracker();
|
||||
const selectedIndices = watch(ChatFormFields.indices);
|
||||
const selectedIndices = watch(PlaygroundFormFields.indices);
|
||||
const { fields, isFetched } = useIndicesFields(selectedIndices);
|
||||
|
||||
useEffect(() => {
|
||||
// Don't merge fields if we haven't fetched them from indices yet, otherwise we'll overwrite save values with a race condition
|
||||
if (!isFetched) return;
|
||||
const {
|
||||
[ChatFormFields.queryFields]: queryFields,
|
||||
[ChatFormFields.sourceFields]: sourceFields,
|
||||
[PlaygroundFormFields.queryFields]: queryFields,
|
||||
[PlaygroundFormFields.sourceFields]: sourceFields,
|
||||
} = getValues();
|
||||
|
||||
const defaultFields = getDefaultQueryFields(fields);
|
||||
|
@ -51,11 +51,11 @@ export const useLoadFieldsByIndices = ({
|
|||
const mergedSourceFields = mergeDefaultAndCurrentValues(defaultSourceFields, sourceFields);
|
||||
|
||||
setValue(
|
||||
ChatFormFields.elasticsearchQuery,
|
||||
PlaygroundFormFields.elasticsearchQuery,
|
||||
createQuery(mergedQueryFields, mergedSourceFields, fields)
|
||||
);
|
||||
setValue(ChatFormFields.queryFields, mergedQueryFields);
|
||||
setValue(ChatFormFields.sourceFields, mergedSourceFields);
|
||||
setValue(PlaygroundFormFields.queryFields, mergedQueryFields);
|
||||
setValue(PlaygroundFormFields.sourceFields, mergedSourceFields);
|
||||
|
||||
usageTracker?.count(AnalyticsEvents.sourceFieldsLoaded, Object.values(fields)?.flat()?.length);
|
||||
}, [fields, getValues, setValue, usageTracker, isFetched]);
|
||||
|
|
|
@ -9,7 +9,7 @@ import { SearchHit } from '@elastic/elasticsearch/lib/api/types';
|
|||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import type { HttpSetup } from '@kbn/core-http-browser';
|
||||
import { APIRoutes, ChatForm, ChatFormFields, Pagination } from '../types';
|
||||
import { APIRoutes, PlaygroundForm, PlaygroundFormFields, Pagination } from '../types';
|
||||
import { useKibana } from './use_kibana';
|
||||
import { DEFAULT_PAGINATION } from '../../common';
|
||||
import { elasticsearchQueryObject } from '../utils/user_query';
|
||||
|
@ -17,8 +17,8 @@ import { elasticsearchQueryObject } from '../utils/user_query';
|
|||
export interface FetchSearchResultsArgs {
|
||||
query: string;
|
||||
pagination: Pagination;
|
||||
indices: ChatForm[ChatFormFields.indices];
|
||||
elasticsearchQuery: ChatForm[ChatFormFields.elasticsearchQuery];
|
||||
indices: PlaygroundForm[PlaygroundFormFields.indices];
|
||||
elasticsearchQuery: PlaygroundForm[PlaygroundFormFields.elasticsearchQuery];
|
||||
http: HttpSetup;
|
||||
}
|
||||
|
||||
|
@ -71,21 +71,21 @@ export const useSearchPreview = ({
|
|||
const {
|
||||
services: { http },
|
||||
} = useKibana();
|
||||
const { getValues } = useFormContext<ChatForm>();
|
||||
const indices = getValues(ChatFormFields.indices);
|
||||
const elasticsearchQuery = getValues(ChatFormFields.elasticsearchQuery);
|
||||
const { getValues } = useFormContext<PlaygroundForm>();
|
||||
const indices = getValues(PlaygroundFormFields.indices);
|
||||
const elasticsearchQuery = getValues(PlaygroundFormFields.elasticsearchQuery);
|
||||
const queryFn = () => {
|
||||
const formData = getValues();
|
||||
const elasticsearchQueryBody = elasticsearchQueryObject(
|
||||
formData[ChatFormFields.elasticsearchQuery],
|
||||
formData[ChatFormFields.userElasticsearchQuery],
|
||||
formData[ChatFormFields.userElasticsearchQueryValidations]
|
||||
formData[PlaygroundFormFields.elasticsearchQuery],
|
||||
formData[PlaygroundFormFields.userElasticsearchQuery],
|
||||
formData[PlaygroundFormFields.userElasticsearchQueryValidations]
|
||||
);
|
||||
return fetchSearchResults({
|
||||
query,
|
||||
pagination,
|
||||
http,
|
||||
indices: formData[ChatFormFields.indices],
|
||||
indices: formData[PlaygroundFormFields.indices],
|
||||
elasticsearchQuery: elasticsearchQueryBody,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@ import { useController } from 'react-hook-form';
|
|||
import { IndexName } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { useCallback } from 'react';
|
||||
import { useIndicesFields } from './use_indices_fields';
|
||||
import { ChatFormFields } from '../types';
|
||||
import { PlaygroundFormFields } from '../types';
|
||||
import { useUsageTracker } from './use_usage_tracker';
|
||||
import { AnalyticsEvents } from '../analytics/constants';
|
||||
|
||||
|
@ -18,12 +18,12 @@ export const useSourceIndicesFields = () => {
|
|||
const {
|
||||
field: { value: selectedIndices, onChange: onIndicesChange },
|
||||
} = useController({
|
||||
name: ChatFormFields.indices,
|
||||
name: PlaygroundFormFields.indices,
|
||||
});
|
||||
const {
|
||||
field: { onChange: onUserQueryChange },
|
||||
} = useController({
|
||||
name: ChatFormFields.userElasticsearchQuery,
|
||||
name: PlaygroundFormFields.userElasticsearchQuery,
|
||||
});
|
||||
const { fields, isLoading: isFieldsLoading } = useIndicesFields(selectedIndices);
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import { useEffect } from 'react';
|
|||
import { UseFormReturn } from 'react-hook-form/dist/types';
|
||||
import { useDebounceFn } from '@kbn/react-hooks';
|
||||
|
||||
import { ChatForm, ChatFormFields } from '../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields } from '../types';
|
||||
import { validateUserElasticSearchQuery } from '../utils/user_query';
|
||||
|
||||
const DEBOUNCE_OPTIONS = { wait: 500 };
|
||||
|
@ -17,17 +17,17 @@ export const useUserQueryValidations = ({
|
|||
watch,
|
||||
setValue,
|
||||
getValues,
|
||||
}: Pick<UseFormReturn<ChatForm>, 'watch' | 'getValues' | 'setValue'>) => {
|
||||
const userElasticsearchQuery = watch(ChatFormFields.userElasticsearchQuery);
|
||||
const elasticsearchQuery = watch(ChatFormFields.elasticsearchQuery);
|
||||
}: Pick<UseFormReturn<PlaygroundForm>, 'watch' | 'getValues' | 'setValue'>) => {
|
||||
const userElasticsearchQuery = watch(PlaygroundFormFields.userElasticsearchQuery);
|
||||
const elasticsearchQuery = watch(PlaygroundFormFields.elasticsearchQuery);
|
||||
|
||||
const userQueryValidation = useDebounceFn(() => {
|
||||
const [esQuery, userInputQuery] = getValues([
|
||||
ChatFormFields.elasticsearchQuery,
|
||||
ChatFormFields.userElasticsearchQuery,
|
||||
PlaygroundFormFields.elasticsearchQuery,
|
||||
PlaygroundFormFields.userElasticsearchQuery,
|
||||
]);
|
||||
const validations = validateUserElasticSearchQuery(userInputQuery, esQuery);
|
||||
setValue(ChatFormFields.userElasticsearchQueryValidations, validations);
|
||||
setValue(PlaygroundFormFields.userElasticsearchQueryValidations, validations);
|
||||
}, DEBOUNCE_OPTIONS);
|
||||
useEffect(() => {
|
||||
userQueryValidation.run();
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
import React, { useMemo } from 'react';
|
||||
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
|
||||
import { PlaygroundProvider } from './providers/playground_provider';
|
||||
import { UnsavedFormProvider } from './providers/unsaved_form_provider';
|
||||
|
||||
import { useKibana } from './hooks/use_kibana';
|
||||
import { App } from './components/app';
|
||||
import { Playground } from './components/playgorund';
|
||||
import { usePlaygroundBreadcrumbs } from './hooks/use_playground_breadcrumbs';
|
||||
|
||||
export const PlaygroundOverview = () => {
|
||||
|
@ -25,18 +25,18 @@ export const PlaygroundOverview = () => {
|
|||
);
|
||||
|
||||
return (
|
||||
<PlaygroundProvider>
|
||||
<KibanaPageTemplate
|
||||
offset={0}
|
||||
restrictWidth={false}
|
||||
data-test-subj="svlPlaygroundPage"
|
||||
grow={false}
|
||||
panelled={false}
|
||||
solutionNav={searchNavigation?.useClassicNavigation(history)}
|
||||
>
|
||||
<App showDocs />
|
||||
{embeddableConsole}
|
||||
</KibanaPageTemplate>
|
||||
</PlaygroundProvider>
|
||||
<KibanaPageTemplate
|
||||
offset={0}
|
||||
restrictWidth={false}
|
||||
data-test-subj="svlPlaygroundPage"
|
||||
grow={false}
|
||||
panelled={false}
|
||||
solutionNav={searchNavigation?.useClassicNavigation(history)}
|
||||
>
|
||||
<UnsavedFormProvider>
|
||||
<Playground showDocs />
|
||||
</UnsavedFormProvider>
|
||||
{embeddableConsole}
|
||||
</KibanaPageTemplate>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* 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, { FC } from 'react';
|
||||
import { QueryClientProvider } from '@tanstack/react-query';
|
||||
import { queryClient } from '../utils/query_client';
|
||||
import { FormProvider } from './form_provider';
|
||||
|
||||
export const PlaygroundProvider: FC<React.PropsWithChildren<{}>> = ({ children }) => {
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<FormProvider>{children}</FormProvider>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
};
|
|
@ -7,11 +7,11 @@
|
|||
|
||||
import React from 'react';
|
||||
import { render, waitFor, act } from '@testing-library/react';
|
||||
import { FormProvider, LOCAL_STORAGE_KEY } from './form_provider';
|
||||
import { UnsavedFormProvider, LOCAL_STORAGE_KEY } from './unsaved_form_provider';
|
||||
import { useLoadFieldsByIndices } from '../hooks/use_load_fields_by_indices';
|
||||
import { useLLMsModels } from '../hooks/use_llms_models';
|
||||
import * as ReactHookForm from 'react-hook-form';
|
||||
import { ChatForm, ChatFormFields } from '../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields } from '../types';
|
||||
import { useSearchParams } from 'react-router-dom-v5-compat';
|
||||
|
||||
jest.mock('../hooks/use_load_fields_by_indices');
|
||||
|
@ -46,7 +46,7 @@ const localStorageMock = (() => {
|
|||
};
|
||||
})() as Storage;
|
||||
|
||||
const DEFAULT_FORM_STATE: Partial<ChatForm> = {
|
||||
const DEFAULT_FORM_STATE: Partial<PlaygroundForm> = {
|
||||
doc_size: 3,
|
||||
prompt: 'You are an assistant for question-answering tasks.',
|
||||
source_fields: {},
|
||||
|
@ -60,7 +60,7 @@ const DEFAULT_FORM_STATE: Partial<ChatForm> = {
|
|||
},
|
||||
};
|
||||
|
||||
describe('FormProvider', () => {
|
||||
describe('UnsavedFormProvider', () => {
|
||||
beforeEach(() => {
|
||||
formHookSpy = jest.spyOn(ReactHookForm, 'useForm');
|
||||
mockUseLLMsModels.mockReturnValue([]);
|
||||
|
@ -74,9 +74,9 @@ describe('FormProvider', () => {
|
|||
|
||||
it('renders the form provider with initial values, no default model', async () => {
|
||||
render(
|
||||
<FormProvider storage={localStorageMock}>
|
||||
<UnsavedFormProvider storage={localStorageMock}>
|
||||
<div>Test Child Component</div>
|
||||
</FormProvider>
|
||||
</UnsavedFormProvider>
|
||||
);
|
||||
|
||||
const { getValues } = formHookSpy.mock.results[0].value;
|
||||
|
@ -95,9 +95,9 @@ describe('FormProvider', () => {
|
|||
mockUseLLMsModels.mockReturnValueOnce(mockModels);
|
||||
|
||||
render(
|
||||
<FormProvider storage={localStorageMock}>
|
||||
<UnsavedFormProvider storage={localStorageMock}>
|
||||
<div>Test Child Component</div>
|
||||
</FormProvider>
|
||||
</UnsavedFormProvider>
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
|
@ -105,7 +105,7 @@ describe('FormProvider', () => {
|
|||
const defaultModel = mockModels.find((model) => !model.disabled);
|
||||
const { getValues } = formHookSpy.mock.results[0].value;
|
||||
|
||||
expect(getValues(ChatFormFields.summarizationModel)).toEqual(defaultModel);
|
||||
expect(getValues(PlaygroundFormFields.summarizationModel)).toEqual(defaultModel);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -118,9 +118,9 @@ describe('FormProvider', () => {
|
|||
mockUseLLMsModels.mockReturnValueOnce(modelsWithAllDisabled);
|
||||
|
||||
render(
|
||||
<FormProvider storage={localStorageMock}>
|
||||
<UnsavedFormProvider storage={localStorageMock}>
|
||||
<div>Test Child Component</div>
|
||||
</FormProvider>
|
||||
</UnsavedFormProvider>
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
|
@ -128,23 +128,23 @@ describe('FormProvider', () => {
|
|||
});
|
||||
|
||||
expect(
|
||||
formHookSpy.mock.results[0].value.getValues(ChatFormFields.summarizationModel)
|
||||
formHookSpy.mock.results[0].value.getValues(PlaygroundFormFields.summarizationModel)
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
it('saves form state to localStorage', async () => {
|
||||
render(
|
||||
<FormProvider storage={localStorageMock}>
|
||||
<UnsavedFormProvider storage={localStorageMock}>
|
||||
<div>Test Child Component</div>
|
||||
</FormProvider>
|
||||
</UnsavedFormProvider>
|
||||
);
|
||||
|
||||
const { setValue } = formHookSpy.mock.results[0].value;
|
||||
|
||||
act(() => {
|
||||
setValue(ChatFormFields.prompt, 'New prompt');
|
||||
setValue(PlaygroundFormFields.prompt, 'New prompt');
|
||||
// omit question from the session state
|
||||
setValue(ChatFormFields.question, 'dont save me');
|
||||
setValue(PlaygroundFormFields.question, 'dont save me');
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
|
@ -174,9 +174,9 @@ describe('FormProvider', () => {
|
|||
);
|
||||
|
||||
render(
|
||||
<FormProvider storage={localStorageMock}>
|
||||
<UnsavedFormProvider storage={localStorageMock}>
|
||||
<div>Test Child Component</div>
|
||||
</FormProvider>
|
||||
</UnsavedFormProvider>
|
||||
);
|
||||
|
||||
const { getValues } = formHookSpy.mock.results[0].value;
|
||||
|
@ -209,9 +209,9 @@ describe('FormProvider', () => {
|
|||
);
|
||||
|
||||
render(
|
||||
<FormProvider storage={localStorageMock}>
|
||||
<UnsavedFormProvider storage={localStorageMock}>
|
||||
<div>Test Child Component</div>
|
||||
</FormProvider>
|
||||
</UnsavedFormProvider>
|
||||
);
|
||||
|
||||
const { getValues } = formHookSpy.mock.results[0].value;
|
||||
|
@ -243,16 +243,16 @@ describe('FormProvider', () => {
|
|||
);
|
||||
|
||||
render(
|
||||
<FormProvider storage={localStorageMock}>
|
||||
<UnsavedFormProvider storage={localStorageMock}>
|
||||
<div>Test Child Component</div>
|
||||
</FormProvider>
|
||||
</UnsavedFormProvider>
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
const { getValues } = formHookSpy.mock.results[0].value;
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getValues(ChatFormFields.indices)).toEqual(['new-index']);
|
||||
expect(getValues(PlaygroundFormFields.indices)).toEqual(['new-index']);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -11,24 +11,24 @@ import { useDebounceFn } from '@kbn/react-hooks';
|
|||
import { useIndicesValidation } from '../hooks/use_indices_validation';
|
||||
import { useLoadFieldsByIndices } from '../hooks/use_load_fields_by_indices';
|
||||
import { useUserQueryValidations } from '../hooks/use_user_query_validations';
|
||||
import { ChatForm, ChatFormFields } from '../types';
|
||||
import { PlaygroundForm, PlaygroundFormFields } from '../types';
|
||||
import { useLLMsModels } from '../hooks/use_llms_models';
|
||||
|
||||
type PartialChatForm = Partial<ChatForm>;
|
||||
type PartialPlaygroundForm = Partial<PlaygroundForm>;
|
||||
export const LOCAL_STORAGE_KEY = 'search_playground_session';
|
||||
export const LOCAL_STORAGE_DEBOUNCE_OPTIONS = { wait: 100 };
|
||||
|
||||
const DEFAULT_FORM_VALUES: PartialChatForm = {
|
||||
const DEFAULT_FORM_VALUES: PartialPlaygroundForm = {
|
||||
prompt: 'You are an assistant for question-answering tasks.',
|
||||
doc_size: 3,
|
||||
source_fields: {},
|
||||
indices: [],
|
||||
summarization_model: undefined,
|
||||
[ChatFormFields.userElasticsearchQuery]: null,
|
||||
[ChatFormFields.userElasticsearchQueryValidations]: undefined,
|
||||
[PlaygroundFormFields.userElasticsearchQuery]: null,
|
||||
[PlaygroundFormFields.userElasticsearchQueryValidations]: undefined,
|
||||
};
|
||||
|
||||
const getLocalSession = (storage: Storage): PartialChatForm => {
|
||||
const getLocalSession = (storage: Storage): PartialPlaygroundForm => {
|
||||
try {
|
||||
const localSessionJSON = storage.getItem(LOCAL_STORAGE_KEY);
|
||||
const sessionState = localSessionJSON ? JSON.parse(localSessionJSON) : {};
|
||||
|
@ -42,23 +42,23 @@ const getLocalSession = (storage: Storage): PartialChatForm => {
|
|||
}
|
||||
};
|
||||
|
||||
const setLocalSession = (formState: PartialChatForm, storage: Storage) => {
|
||||
const setLocalSession = (formState: PartialPlaygroundForm, storage: Storage) => {
|
||||
// omit question and search_query from the session state
|
||||
const {
|
||||
question,
|
||||
search_query: _searchQuery,
|
||||
[ChatFormFields.userElasticsearchQueryValidations]: _queryValidations,
|
||||
[PlaygroundFormFields.userElasticsearchQueryValidations]: _queryValidations,
|
||||
...state
|
||||
} = formState;
|
||||
|
||||
storage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(state));
|
||||
};
|
||||
|
||||
interface FormProviderProps {
|
||||
interface UnsavedFormProviderProps {
|
||||
storage?: Storage;
|
||||
}
|
||||
|
||||
export const FormProvider: React.FC<React.PropsWithChildren<FormProviderProps>> = ({
|
||||
export const UnsavedFormProvider: React.FC<React.PropsWithChildren<UnsavedFormProviderProps>> = ({
|
||||
children,
|
||||
storage = localStorage,
|
||||
}) => {
|
||||
|
@ -69,8 +69,8 @@ export const FormProvider: React.FC<React.PropsWithChildren<FormProviderProps>>
|
|||
|
||||
return index ? [index] : null;
|
||||
}, [searchParams]);
|
||||
const sessionState: PartialChatForm = useMemo(() => getLocalSession(storage), [storage]);
|
||||
const form = useForm<ChatForm>({
|
||||
const sessionState: PartialPlaygroundForm = useMemo(() => getLocalSession(storage), [storage]);
|
||||
const form = useForm<PlaygroundForm>({
|
||||
defaultValues: {
|
||||
...sessionState,
|
||||
indices: [],
|
||||
|
@ -94,23 +94,23 @@ export const FormProvider: React.FC<React.PropsWithChildren<FormProviderProps>>
|
|||
const setLocalSessionDebounce = useDebounceFn(setLocalSession, LOCAL_STORAGE_DEBOUNCE_OPTIONS);
|
||||
useEffect(() => {
|
||||
const subscription = form.watch((values) =>
|
||||
setLocalSessionDebounce.run(values as PartialChatForm, storage)
|
||||
setLocalSessionDebounce.run(values as PartialPlaygroundForm, storage)
|
||||
);
|
||||
return () => subscription.unsubscribe();
|
||||
}, [form, storage, setLocalSessionDebounce]);
|
||||
|
||||
useEffect(() => {
|
||||
const defaultModel = models.find((model) => !model.disabled);
|
||||
const currentModel = form.getValues(ChatFormFields.summarizationModel);
|
||||
const currentModel = form.getValues(PlaygroundFormFields.summarizationModel);
|
||||
|
||||
if (defaultModel && (!currentModel || !models.find((model) => currentModel.id === model.id))) {
|
||||
form.setValue(ChatFormFields.summarizationModel, defaultModel);
|
||||
form.setValue(PlaygroundFormFields.summarizationModel, defaultModel);
|
||||
}
|
||||
}, [form, models]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isValidatedIndices) {
|
||||
form.setValue(ChatFormFields.indices, validIndices);
|
||||
form.setValue(PlaygroundFormFields.indices, validIndices);
|
||||
}
|
||||
}, [form, isValidatedIndices, validIndices]);
|
||||
|
|
@ -71,7 +71,7 @@ export interface AppPluginStartDependencies {
|
|||
|
||||
export type AppServicesContext = CoreStart & AppPluginStartDependencies;
|
||||
|
||||
export enum ChatFormFields {
|
||||
export enum PlaygroundFormFields {
|
||||
question = 'question',
|
||||
citations = 'citations',
|
||||
prompt = 'prompt',
|
||||
|
@ -86,19 +86,19 @@ export enum ChatFormFields {
|
|||
searchQuery = 'search_query',
|
||||
}
|
||||
|
||||
export interface ChatForm {
|
||||
[ChatFormFields.question]: string;
|
||||
[ChatFormFields.prompt]: string;
|
||||
[ChatFormFields.citations]: boolean;
|
||||
[ChatFormFields.indices]: string[];
|
||||
[ChatFormFields.summarizationModel]: LLMModel;
|
||||
[ChatFormFields.elasticsearchQuery]: { retriever: any }; // RetrieverContainer leads to "Type instantiation is excessively deep and possibly infinite" error
|
||||
[ChatFormFields.sourceFields]: { [index: string]: string[] };
|
||||
[ChatFormFields.docSize]: number;
|
||||
[ChatFormFields.queryFields]: { [index: string]: string[] };
|
||||
[ChatFormFields.searchQuery]: string;
|
||||
[ChatFormFields.userElasticsearchQuery]: string | null | undefined;
|
||||
[ChatFormFields.userElasticsearchQueryValidations]: UserQueryValidations | undefined;
|
||||
export interface PlaygroundForm {
|
||||
[PlaygroundFormFields.question]: string;
|
||||
[PlaygroundFormFields.prompt]: string;
|
||||
[PlaygroundFormFields.citations]: boolean;
|
||||
[PlaygroundFormFields.indices]: string[];
|
||||
[PlaygroundFormFields.summarizationModel]: LLMModel;
|
||||
[PlaygroundFormFields.elasticsearchQuery]: { retriever: any }; // RetrieverContainer leads to "Type instantiation is excessively deep and possibly infinite" error
|
||||
[PlaygroundFormFields.sourceFields]: { [index: string]: string[] };
|
||||
[PlaygroundFormFields.docSize]: number;
|
||||
[PlaygroundFormFields.queryFields]: { [index: string]: string[] };
|
||||
[PlaygroundFormFields.searchQuery]: string;
|
||||
[PlaygroundFormFields.userElasticsearchQuery]: string | null | undefined;
|
||||
[PlaygroundFormFields.userElasticsearchQueryValidations]: UserQueryValidations | undefined;
|
||||
}
|
||||
|
||||
export interface UserQueryValidations {
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
|
||||
import deepEqual from 'fast-deep-equal';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { ChatForm, ChatFormFields, UserQueryValidations } from '../types';
|
||||
import type { PlaygroundForm, PlaygroundFormFields, UserQueryValidations } from '../types';
|
||||
|
||||
export const validateUserElasticSearchQuery = (
|
||||
userQuery: ChatForm[ChatFormFields.userElasticsearchQuery],
|
||||
elasticsearchQuery: ChatForm[ChatFormFields.elasticsearchQuery]
|
||||
userQuery: PlaygroundForm[PlaygroundFormFields.userElasticsearchQuery],
|
||||
elasticsearchQuery: PlaygroundForm[PlaygroundFormFields.elasticsearchQuery]
|
||||
): UserQueryValidations => {
|
||||
if (userQuery === null || userQuery === undefined || typeof userQuery !== 'string') {
|
||||
return { isValid: false, isUserCustomized: false };
|
||||
|
@ -59,9 +59,9 @@ export const disableExecuteQuery = (
|
|||
};
|
||||
|
||||
export const elasticsearchQueryString = (
|
||||
elasticsearchQuery: ChatForm[ChatFormFields.elasticsearchQuery],
|
||||
userElasticsearchQuery: ChatForm[ChatFormFields.userElasticsearchQuery],
|
||||
userElasticsearchQueryValidations: ChatForm[ChatFormFields.userElasticsearchQueryValidations]
|
||||
elasticsearchQuery: PlaygroundForm[PlaygroundFormFields.elasticsearchQuery],
|
||||
userElasticsearchQuery: PlaygroundForm[PlaygroundFormFields.userElasticsearchQuery],
|
||||
userElasticsearchQueryValidations: PlaygroundForm[PlaygroundFormFields.userElasticsearchQueryValidations]
|
||||
) => {
|
||||
if (!userElasticsearchQuery || userElasticsearchQueryValidations?.isUserCustomized === false) {
|
||||
return JSON.stringify(elasticsearchQuery);
|
||||
|
@ -73,9 +73,9 @@ export const elasticsearchQueryString = (
|
|||
};
|
||||
|
||||
export const elasticsearchQueryObject = (
|
||||
elasticsearchQuery: ChatForm[ChatFormFields.elasticsearchQuery],
|
||||
userElasticsearchQuery: ChatForm[ChatFormFields.userElasticsearchQuery],
|
||||
userElasticsearchQueryValidations: ChatForm[ChatFormFields.userElasticsearchQueryValidations]
|
||||
elasticsearchQuery: PlaygroundForm[PlaygroundFormFields.elasticsearchQuery],
|
||||
userElasticsearchQuery: PlaygroundForm[PlaygroundFormFields.userElasticsearchQuery],
|
||||
userElasticsearchQueryValidations: PlaygroundForm[PlaygroundFormFields.userElasticsearchQueryValidations]
|
||||
): { retriever: any } => {
|
||||
if (!userElasticsearchQuery || userElasticsearchQueryValidations?.isUserCustomized === false) {
|
||||
return elasticsearchQuery;
|
||||
|
@ -87,5 +87,5 @@ export const elasticsearchQueryObject = (
|
|||
};
|
||||
|
||||
export const formatElasticsearchQueryString = (
|
||||
elasticsearchQuery: ChatForm[ChatFormFields.elasticsearchQuery]
|
||||
elasticsearchQuery: PlaygroundForm[PlaygroundFormFields.elasticsearchQuery]
|
||||
) => JSON.stringify(elasticsearchQuery, null, 2);
|
||||
|
|
Loading…
Add table
Reference in a new issue