From 1635bdf98d453556bab9a629ce4cf75ec9252954 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Mon, 19 Feb 2024 16:29:38 +0100 Subject: [PATCH 1/5] [AI Playground] Update indicie design. Use list instead of table --- .../sources_panel/add_indices_field.tsx | 31 +++++------- .../components/sources_panel/indices_list.tsx | 43 ++++++++++++++++ .../sources_panel/indices_table.tsx | 50 ------------------- .../sources_panel/sources_panel.tsx | 11 +++- 4 files changed, 64 insertions(+), 71 deletions(-) create mode 100644 packages/kbn-ai-playground/components/sources_panel/indices_list.tsx delete mode 100644 packages/kbn-ai-playground/components/sources_panel/indices_table.tsx diff --git a/packages/kbn-ai-playground/components/sources_panel/add_indices_field.tsx b/packages/kbn-ai-playground/components/sources_panel/add_indices_field.tsx index 0665e1d08d1b22..bfdce5235e0e15 100644 --- a/packages/kbn-ai-playground/components/sources_panel/add_indices_field.tsx +++ b/packages/kbn-ai-playground/components/sources_panel/add_indices_field.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiButtonIcon, EuiComboBox, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiComboBox } from '@elastic/eui'; import React from 'react'; import { EuiComboBoxOptionOption } from '@elastic/eui/src/components/combo_box/types'; import { i18n } from '@kbn/i18n'; @@ -27,23 +27,16 @@ export const AddIndicesField = ({ addIndices }) => { }; return ( - - - options.find((option) => option.key === index)! - )} - onChange={onChange} - /> - - - - - + options.find((option) => option.key === index)! + )} + onChange={onChange} + /> ); }; diff --git a/packages/kbn-ai-playground/components/sources_panel/indices_list.tsx b/packages/kbn-ai-playground/components/sources_panel/indices_list.tsx new file mode 100644 index 00000000000000..13abd9678d8df3 --- /dev/null +++ b/packages/kbn-ai-playground/components/sources_panel/indices_list.tsx @@ -0,0 +1,43 @@ +/* + * 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 { EuiFormRow, EuiListGroup, EuiListGroupItem } from '@elastic/eui'; +import React from 'react'; +import { i18n } from '@kbn/i18n'; + +interface IndicesListProps { + indices: Array<{ id: string; name: string }>; + onRemoveClick: (index: string) => void; + hasBorder?: boolean; +} + +export const IndicesList: React.FC = ({ indices, onRemoveClick, hasBorder }) => ( + + + {indices.map((index) => ( + onRemoveClick(index.id), + }} + /> + ))} + + +); diff --git a/packages/kbn-ai-playground/components/sources_panel/indices_table.tsx b/packages/kbn-ai-playground/components/sources_panel/indices_table.tsx deleted file mode 100644 index 55398fa44fbcbf..00000000000000 --- a/packages/kbn-ai-playground/components/sources_panel/indices_table.tsx +++ /dev/null @@ -1,50 +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 { EuiBasicTable } from '@elastic/eui'; -import React from 'react'; -import { i18n } from '@kbn/i18n'; - -interface IndicesTableProps { - onRemoveClick: (index: string) => void; -} - -export const IndicesTable: React.FC = ({ onRemoveClick }) => { - return ( - onRemoveClick(index.id), - }, - ], - }, - ]} - items={[ - { id: '1', name: 'search-index' }, - { id: '2', name: 'search-books' }, - ]} - /> - ); -}; diff --git a/packages/kbn-ai-playground/components/sources_panel/sources_panel.tsx b/packages/kbn-ai-playground/components/sources_panel/sources_panel.tsx index 4516ea7f73f945..0d2b5b1ecf6a6c 100644 --- a/packages/kbn-ai-playground/components/sources_panel/sources_panel.tsx +++ b/packages/kbn-ai-playground/components/sources_panel/sources_panel.tsx @@ -14,7 +14,7 @@ import { EuiTitle, useGeneratedHtmlId, } from '@elastic/eui'; -import { IndicesTable } from './indices_table'; +import { IndicesList } from './indices_list'; import { AddIndicesField } from './add_indices_field'; interface SourcesFlyoutProps {} @@ -40,7 +40,14 @@ export const SourcesPanel: React.FC = () => { > - + From c363bed46829db383c64f8c001614b5658ef1350 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Mon, 19 Feb 2024 18:50:43 +0100 Subject: [PATCH 2/5] [AI Playground] Update selected list --- .../sources_panel/add_indices_field.tsx | 58 +++++++++++-------- .../components/sources_panel/indices_list.tsx | 10 +++- .../sources_panel/sources_panel.tsx | 24 ++++---- 3 files changed, 51 insertions(+), 41 deletions(-) diff --git a/packages/kbn-ai-playground/components/sources_panel/add_indices_field.tsx b/packages/kbn-ai-playground/components/sources_panel/add_indices_field.tsx index bfdce5235e0e15..4cd44c77dc3e63 100644 --- a/packages/kbn-ai-playground/components/sources_panel/add_indices_field.tsx +++ b/packages/kbn-ai-playground/components/sources_panel/add_indices_field.tsx @@ -5,38 +5,46 @@ * 2.0. */ -import { EuiComboBox } from '@elastic/eui'; +import { EuiFormRow, EuiSuperSelect } from '@elastic/eui'; import React from 'react'; -import { EuiComboBoxOptionOption } from '@elastic/eui/src/components/combo_box/types'; import { i18n } from '@kbn/i18n'; -const options = [ - { label: 'search-index1', key: 'id-1' }, - { label: 'search-index1', key: 'id-1' }, -]; +interface AddIndicesFieldProps { + indices: string[]; + selectedIndices: string[]; + addIndex: (index: string) => void; +} -export const AddIndicesField = ({ addIndices }) => { - const [selectedIndices, setSelectedIndices] = React.useState([]); - const handleAddIndices = () => { - addIndices(selectedIndices); - }; - const onChange = (selectedOptions: EuiComboBoxOptionOption[]) => { - setSelectedIndices( - selectedOptions.filter((option) => option && !!option.key).map((option) => option.key) - ); +export const AddIndicesField: React.FC = ({ + selectedIndices, + indices, + addIndex, +}) => { + const onChange = (selectedIndex: string) => { + addIndex(selectedIndex); }; return ( - options.find((option) => option.key === index)! - )} - onChange={onChange} - /> + label={i18n.translate('aiPlayground.sources.addIndex.label', { + defaultMessage: 'Add index', + })} + labelType="legend" + > + ({ + value: index, + inputDisplay: index, + disabled: selectedIndices.includes(index), + }))} + onChange={onChange} + hasDividers + /> + ); }; diff --git a/packages/kbn-ai-playground/components/sources_panel/indices_list.tsx b/packages/kbn-ai-playground/components/sources_panel/indices_list.tsx index 13abd9678d8df3..f105af498ff76b 100644 --- a/packages/kbn-ai-playground/components/sources_panel/indices_list.tsx +++ b/packages/kbn-ai-playground/components/sources_panel/indices_list.tsx @@ -10,22 +10,25 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; interface IndicesListProps { - indices: Array<{ id: string; name: string }>; + indices: string[]; onRemoveClick: (index: string) => void; hasBorder?: boolean; } export const IndicesList: React.FC = ({ indices, onRemoveClick, hasBorder }) => ( {indices.map((index) => ( = ({ indices, onRemoveClick }), color: 'text', iconType: 'minusInCircle', - onClick: () => onRemoveClick(index.id), + onClick: () => onRemoveClick(index), + disabled: indices.length === 1, }} /> ))} diff --git a/packages/kbn-ai-playground/components/sources_panel/sources_panel.tsx b/packages/kbn-ai-playground/components/sources_panel/sources_panel.tsx index 0d2b5b1ecf6a6c..f6a008bf1e30a1 100644 --- a/packages/kbn-ai-playground/components/sources_panel/sources_panel.tsx +++ b/packages/kbn-ai-playground/components/sources_panel/sources_panel.tsx @@ -21,12 +21,13 @@ interface SourcesFlyoutProps {} export const SourcesPanel: React.FC = () => { const accordionId = useGeneratedHtmlId({ prefix: 'sourceAccordion' }); - const [indices, setIndices] = React.useState([]); - const addIndices = (newIndices: string[]) => { - setIndices([...indices, ...newIndices]); + const indices = ['search-index', 'search-books']; + const [selectedIndices, setSelectedIndices] = React.useState([]); + const addIndex = (newIndex: string) => { + setSelectedIndices([...selectedIndices, newIndex]); }; const removeIndex = (index: string) => { - setIndices(indices.filter((i: string) => i !== index)); + setSelectedIndices(selectedIndices.filter((indexName) => indexName !== index)); }; return ( @@ -40,18 +41,15 @@ export const SourcesPanel: React.FC = () => { > - + - + From 58776481280ce220740897f668b1df790a4e7925 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Mon, 19 Feb 2024 19:25:06 +0100 Subject: [PATCH 3/5] [AI Playground] Add callout to sources --- .../components/sources_panel/sources_panel.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/kbn-ai-playground/components/sources_panel/sources_panel.tsx b/packages/kbn-ai-playground/components/sources_panel/sources_panel.tsx index f6a008bf1e30a1..21e8dfc03f96fe 100644 --- a/packages/kbn-ai-playground/components/sources_panel/sources_panel.tsx +++ b/packages/kbn-ai-playground/components/sources_panel/sources_panel.tsx @@ -9,6 +9,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiAccordion, + EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiTitle, @@ -40,6 +41,16 @@ export const SourcesPanel: React.FC = () => { } > + + + + From 3b5b405f1ebab601265067c283c8e6e2ccbc0885 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Mon, 19 Feb 2024 19:28:48 +0100 Subject: [PATCH 4/5] [AI Playground] Rename sources panel --- packages/kbn-ai-playground/components/chat.tsx | 14 ++++---------- ...sources_panel.tsx => sources_panel_sidebar.tsx} | 4 ++-- 2 files changed, 6 insertions(+), 12 deletions(-) rename packages/kbn-ai-playground/components/sources_panel/{sources_panel.tsx => sources_panel_sidebar.tsx} (94%) diff --git a/packages/kbn-ai-playground/components/chat.tsx b/packages/kbn-ai-playground/components/chat.tsx index a99c2f02e9e014..7625a173f67ae4 100644 --- a/packages/kbn-ai-playground/components/chat.tsx +++ b/packages/kbn-ai-playground/components/chat.tsx @@ -20,26 +20,20 @@ import { import { v4 as uuidv4 } from 'uuid'; import { i18n } from '@kbn/i18n'; -import { useChat, UseChatHelpers } from '@elastic/ai-assist/dist/react'; +import { useChat } from '@elastic/ai-assist/dist/react'; -import { - AIPlaygroundPluginStartDeps, - ChatForm, - ChatFormFields, - Message, - MessageRole, -} from '../types'; +import { AIPlaygroundPluginStartDeps, ChatForm, ChatFormFields, MessageRole } from '../types'; import { MessageList } from './message_list/message_list'; import { QuestionInput } from './question_input'; import { OpenAIKeyField } from './open_ai_key_field'; import { InstructionsField } from './instructions_field'; import { IncludeCitationsField } from './include_citations_field'; +import { SourcesPanelSidebar } from './sources_panel/sources_panel_sidebar'; import { TelegramIcon } from './telegram_icon'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { transformFromChatMessages } from '../utils/transformToMessages'; -import { SourcesPanel } from '@kbn/ai-playground/components/sources_panel/sources_panel'; export const Chat = () => { const { euiTheme } = useEuiTheme(); @@ -202,7 +196,7 @@ export const Chat = () => { )} /> - + diff --git a/packages/kbn-ai-playground/components/sources_panel/sources_panel.tsx b/packages/kbn-ai-playground/components/sources_panel/sources_panel_sidebar.tsx similarity index 94% rename from packages/kbn-ai-playground/components/sources_panel/sources_panel.tsx rename to packages/kbn-ai-playground/components/sources_panel/sources_panel_sidebar.tsx index 21e8dfc03f96fe..c9bd8f72273275 100644 --- a/packages/kbn-ai-playground/components/sources_panel/sources_panel.tsx +++ b/packages/kbn-ai-playground/components/sources_panel/sources_panel_sidebar.tsx @@ -18,9 +18,9 @@ import { import { IndicesList } from './indices_list'; import { AddIndicesField } from './add_indices_field'; -interface SourcesFlyoutProps {} +interface SourcesPanelSidebarProps {} -export const SourcesPanel: React.FC = () => { +export const SourcesPanelSidebar: React.FC = () => { const accordionId = useGeneratedHtmlId({ prefix: 'sourceAccordion' }); const indices = ['search-index', 'search-books']; const [selectedIndices, setSelectedIndices] = React.useState([]); From d874f0bbadc5010b525cb581454c652759a43e23 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Mon, 19 Feb 2024 23:32:41 +0100 Subject: [PATCH 5/5] [AI Playground] Add source panel for beginning a chat --- .../components/empty_index.tsx | 5 +- .../sources_panel/add_indices_field.tsx | 54 +++++++------- .../components/sources_panel/indices_list.tsx | 62 ++++++++-------- .../sources_panel/indices_table.tsx | 47 ++++++++++++ .../sources_panel_empty_prompt.tsx | 71 +++++++++++++++++++ .../sources_panel/sources_panel_sidebar.tsx | 2 +- 6 files changed, 179 insertions(+), 62 deletions(-) create mode 100644 packages/kbn-ai-playground/components/sources_panel/indices_table.tsx create mode 100644 packages/kbn-ai-playground/components/sources_panel/sources_panel_empty_prompt.tsx diff --git a/packages/kbn-ai-playground/components/empty_index.tsx b/packages/kbn-ai-playground/components/empty_index.tsx index c8eee84a92edcd..3b5575159bb318 100644 --- a/packages/kbn-ai-playground/components/empty_index.tsx +++ b/packages/kbn-ai-playground/components/empty_index.tsx @@ -10,6 +10,7 @@ import React from 'react'; import { EuiButton, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { SourcesPanelEmptyPrompt } from './sources_panel/sources_panel_empty_prompt'; interface EmptyIndexProps { onCreateIndexClick: () => void; @@ -17,7 +18,7 @@ interface EmptyIndexProps { export const EmptyIndex: React.FC = ({ onCreateIndexClick }) => { return ( - + = ({ onCreateIndexClick }) => /> + + ); }; diff --git a/packages/kbn-ai-playground/components/sources_panel/add_indices_field.tsx b/packages/kbn-ai-playground/components/sources_panel/add_indices_field.tsx index 4cd44c77dc3e63..d47a7a02216baa 100644 --- a/packages/kbn-ai-playground/components/sources_panel/add_indices_field.tsx +++ b/packages/kbn-ai-playground/components/sources_panel/add_indices_field.tsx @@ -12,39 +12,33 @@ import { i18n } from '@kbn/i18n'; interface AddIndicesFieldProps { indices: string[]; selectedIndices: string[]; - addIndex: (index: string) => void; + onIndexSelect: (index: string) => void; } export const AddIndicesField: React.FC = ({ selectedIndices, indices, - addIndex, -}) => { - const onChange = (selectedIndex: string) => { - addIndex(selectedIndex); - }; - - return ( - ( + + - ({ - value: index, - inputDisplay: index, - disabled: selectedIndices.includes(index), - }))} - onChange={onChange} - hasDividers - /> - - ); -}; + fullWidth + options={indices.map((index) => ({ + value: index, + inputDisplay: index, + disabled: selectedIndices.includes(index), + }))} + onChange={onIndexSelect} + hasDividers + /> + +); diff --git a/packages/kbn-ai-playground/components/sources_panel/indices_list.tsx b/packages/kbn-ai-playground/components/sources_panel/indices_list.tsx index f105af498ff76b..5e554e5e585337 100644 --- a/packages/kbn-ai-playground/components/sources_panel/indices_list.tsx +++ b/packages/kbn-ai-playground/components/sources_panel/indices_list.tsx @@ -15,33 +15,35 @@ interface IndicesListProps { hasBorder?: boolean; } -export const IndicesList: React.FC = ({ indices, onRemoveClick, hasBorder }) => ( - - - {indices.map((index) => ( - onRemoveClick(index), - disabled: indices.length === 1, - }} - /> - ))} - - -); +export const IndicesList: React.FC = ({ indices, onRemoveClick, hasBorder }) => + indices?.length ? ( + + + {indices.map((index) => ( + onRemoveClick(index), + disabled: indices.length === 1, + }} + /> + ))} + + + ) : null; diff --git a/packages/kbn-ai-playground/components/sources_panel/indices_table.tsx b/packages/kbn-ai-playground/components/sources_panel/indices_table.tsx new file mode 100644 index 00000000000000..9f38be6efdfe6c --- /dev/null +++ b/packages/kbn-ai-playground/components/sources_panel/indices_table.tsx @@ -0,0 +1,47 @@ +/* + * 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 { EuiBasicTable, EuiLink } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; + +interface IndicesTableProps { + indices: string[]; + onRemoveClick: (index: string) => void; +} + +export const IndicesTable: React.FC = ({ indices, onRemoveClick }) => ( + ({ index }))} + columns={[ + { + field: 'index', + name: i18n.translate('aiPlayground.sources.indices.table.label', { + defaultMessage: 'Selected indices', + }), + truncateText: true, + render: (index: string) => {index}, + }, + { + actions: [ + { + type: 'icon', + name: i18n.translate('aiPlayground.sources.indices.table.remove.label', { + defaultMessage: 'Remove', + }), + description: i18n.translate('aiPlayground.sources.indices.table.remove.description', { + defaultMessage: 'Remove index', + }), + icon: 'minusInCircle', + onClick: (item: { index: string }) => onRemoveClick(item.index), + }, + ], + }, + ]} + hasActions + /> +); diff --git a/packages/kbn-ai-playground/components/sources_panel/sources_panel_empty_prompt.tsx b/packages/kbn-ai-playground/components/sources_panel/sources_panel_empty_prompt.tsx new file mode 100644 index 00000000000000..0e4a6144d9b830 --- /dev/null +++ b/packages/kbn-ai-playground/components/sources_panel/sources_panel_empty_prompt.tsx @@ -0,0 +1,71 @@ +/* + * 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 { + EuiPanel, + EuiTitle, + EuiText, + EuiLink, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, +} from '@elastic/eui'; +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { AddIndicesField } from './add_indices_field'; +import { IndicesTable } from './indices_table'; + +export const SourcesPanelEmptyPrompt: React.FC = () => { + const indices = ['search-index', 'search-books']; + const [selectedIndices, setSelectedIndices] = React.useState([]); + const addIndex = (newIndex: string) => { + setSelectedIndices([...selectedIndices, newIndex]); + }; + const removeIndex = (index: string) => { + setSelectedIndices(selectedIndices.filter((indexName) => indexName !== index)); + }; + + return ( + + +
+ +
+
+ + + + + +

+ +

+
+ + {!!selectedIndices?.length && ( + + + + )} + + + + +
+
+ ); +}; diff --git a/packages/kbn-ai-playground/components/sources_panel/sources_panel_sidebar.tsx b/packages/kbn-ai-playground/components/sources_panel/sources_panel_sidebar.tsx index c9bd8f72273275..57230127c4e3b8 100644 --- a/packages/kbn-ai-playground/components/sources_panel/sources_panel_sidebar.tsx +++ b/packages/kbn-ai-playground/components/sources_panel/sources_panel_sidebar.tsx @@ -59,7 +59,7 @@ export const SourcesPanelSidebar: React.FC = () => {