Skip to content

Commit

Permalink
Merge pull request elastic#43 from CoenWarmer/storybook
Browse files Browse the repository at this point in the history
  • Loading branch information
CoenWarmer authored Aug 15, 2023
2 parents 4474daf + fff489b commit 54301ca
Show file tree
Hide file tree
Showing 13 changed files with 306 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,10 @@ import { MissingCredentialsCallout } from '../missing_credentials_callout';
import { ChatHeader } from './chat_header';
import { ChatPromptEditor } from './chat_prompt_editor';
import { ChatTimeline } from './chat_timeline';
import { KnowledgeBaseCallout } from './knowledge_base_callout';

const containerClassName = css`
max-height: 100%;
max-width: 100%;
max-width: 800px;
`;

const timelineClassName = css`
Expand All @@ -47,20 +46,23 @@ export function ChatBody({
messages,
connectors,
knowledgeBase,
currentUser,
connectorsManagementHref,
currentUser,
onChatUpdate,
onChatComplete,
onSaveTitle,
}: {
title: string;
loading: boolean;
messages: Message[];
connectors: UseGenAIConnectorsResult;
knowledgeBase: UseKnowledgeBaseResult;
currentUser?: Pick<AuthenticatedUser, 'full_name' | 'username'>;
connectorsManagementHref: string;
conversationId?: string;
currentUser?: Pick<AuthenticatedUser, 'full_name' | 'username'>;
onChatUpdate: (messages: Message[]) => void;
onChatComplete: (messages: Message[]) => void;
onSaveTitle: (title: string) => void;
}) {
const chatService = useObservabilityAIAssistantChatService();

Expand Down Expand Up @@ -142,7 +144,7 @@ export function ChatBody({
<>
<EuiFlexItem grow className={timelineClassName}>
<div ref={timelineContainerRef}>
<EuiPanel hasBorder={false} hasShadow={false} paddingSize="m">
<EuiPanel hasBorder={false} hasShadow={false} paddingSize="s">
<ChatTimeline
items={timeline.items}
onEdit={timeline.onEdit}
Expand All @@ -157,12 +159,13 @@ export function ChatBody({
<EuiHorizontalRule margin="none" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiPanel hasBorder={false} hasShadow={false} paddingSize="m">
<EuiPanel hasBorder={false} hasShadow={false} paddingSize="s">
<ChatPromptEditor
loading={isLoading}
disabled={!connectors.selectedConnector}
onSubmit={timeline.onSubmit}
/>
<EuiSpacer size="m" />
</EuiPanel>
</EuiFlexItem>
</>
Expand All @@ -172,12 +175,13 @@ export function ChatBody({
return (
<EuiFlexGroup direction="column" gutterSize="none" className={containerClassName}>
<EuiFlexItem grow={false}>
<EuiPanel hasBorder={false} hasShadow={false} paddingSize="m">
<ChatHeader title={title} connectors={connectors} loading={loading} />
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<KnowledgeBaseCallout knowledgeBase={knowledgeBase} />
<ChatHeader
title={title}
connectors={connectors}
knowledgeBase={knowledgeBase}
loading={loading}
onSaveTitle={onSaveTitle}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiHorizontalRule margin="none" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default meta;

export const ChatHeaderLoaded: ComponentStoryObj<typeof Component> = {
args: {
title: 'My conversation',
title: 'My conversation jdhf lskdjhfsdlk jfh sdlkjfh sdlkfjhsd klfjhds flkjdsh flksdjh fl',
connectors: {
loading: false,
selectedConnector: 'gpt-4',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,100 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiTitle, useEuiTheme } from '@elastic/eui';
import React, { useRef } from 'react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiInlineEditTitle,
EuiLoadingSpinner,
EuiPanel,
useEuiTheme,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { css } from '@emotion/css';
import { UseGenAIConnectorsResult } from '../../hooks/use_genai_connectors';
import { AssistantAvatar } from '../assistant_avatar';
import { ConnectorSelectorBase } from '../connector_selector/connector_selector_base';
import { EMPTY_CONVERSATION_TITLE } from '../../i18n';
import { KnowledgeBaseCallout } from './knowledge_base_callout';
import { useUnmountAndRemountWhenPropChanges } from '../../hooks/use_unmount_and_remount_when_prop_changes';
import type { UseGenAIConnectorsResult } from '../../hooks/use_genai_connectors';
import type { UseKnowledgeBaseResult } from '../../hooks/use_knowledge_base';

const minWidthClassName = css`
min-width: 0;
`;

export function ChatHeader({
title,
loading,
knowledgeBase,
connectors,
onSaveTitle,
}: {
title: string;
loading: boolean;
knowledgeBase: UseKnowledgeBaseResult;
connectors: UseGenAIConnectorsResult;
onSaveTitle?: (title: string) => void;
}) {
const hasTitle = !!title;

const displayedTitle = title || EMPTY_CONVERSATION_TITLE;

const theme = useEuiTheme();

// Component only works uncontrolled at the moment, so need to unmount and remount.
const shouldRender = useUnmountAndRemountWhenPropChanges(displayedTitle);

const inputRef = useRef<HTMLInputElement>(null);

return (
<EuiFlexGroup alignItems="center" gutterSize="l">
<EuiFlexItem grow={false}>
{loading ? <EuiLoadingSpinner size="l" /> : <AssistantAvatar size="l" />}
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexGroup direction="column" gutterSize="none" justifyContent="center">
<EuiFlexItem grow={false}>
<EuiTitle
size="m"
className={css`
color: ${hasTitle ? theme.euiTheme.colors.text : theme.euiTheme.colors.subduedText};
`}
>
<h2>{displayedTitle}</h2>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<ConnectorSelectorBase {...connectors} />
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
<EuiPanel
paddingSize="s"
hasBorder={false}
hasShadow={false}
borderRadius="none"
className={css`
padding-top: 16px;
padding-bottom: 16px;
`}
>
<EuiFlexGroup alignItems="flexStart" gutterSize="m" responsive={false}>
<EuiFlexItem grow={false}>
{loading ? <EuiLoadingSpinner size="xl" /> : <AssistantAvatar size="m" />}
</EuiFlexItem>
<EuiFlexItem grow className={minWidthClassName}>
<EuiFlexGroup direction="column" gutterSize="none" className={minWidthClassName}>
<EuiFlexItem grow={false} className={minWidthClassName}>
{shouldRender ? (
<EuiInlineEditTitle
heading="h2"
size="s"
defaultValue={displayedTitle}
className={css`
color: ${hasTitle
? theme.euiTheme.colors.text
: theme.euiTheme.colors.subduedText};
`}
inputAriaLabel={i18n.translate(
'xpack.observabilityAiAssistant.chatHeader.editConversationInput',
{ defaultMessage: 'Edit conversation' }
)}
editModeProps={{ inputProps: { inputRef } }}
isReadOnly={!Boolean(onSaveTitle)}
onSave={onSaveTitle}
/>
) : null}
</EuiFlexItem>
<EuiFlexItem>
<KnowledgeBaseCallout knowledgeBase={knowledgeBase} />
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<ConnectorSelectorBase {...connectors} />
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export function ChatPromptEditor({
} catch (_) {
setPrompt(currentPrompt);
}
}, [functionPayload, onSubmit, prompt, selectedFunctionName, loading]);
}, [functionPayload, loading, onSubmit, prompt, selectedFunctionName]);

useEffect(() => {
const keyboardListener = (event: KeyboardEvent) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
* 2.0.
*/

import React, { ReactNode } from 'react';
import { css } from '@emotion/react';
import { compact } from 'lodash';
import { EuiCommentList } from '@elastic/eui';
import type { AuthenticatedUser } from '@kbn/security-plugin/common';
import { compact } from 'lodash';
import React, { ReactNode } from 'react';
import { type Message } from '../../../common';

import type { Feedback } from '../feedback_buttons';
import { ChatItem } from './chat_item';
import type { Feedback } from '../feedback_buttons';
import type { Message } from '../../../common';

export interface ChatTimelineItem
extends Pick<Message['message'], 'role' | 'content' | 'function_call'> {
Expand Down Expand Up @@ -50,7 +50,11 @@ export function ChatTimeline({
onStopGenerating,
}: ChatTimelineProps) {
return (
<EuiCommentList>
<EuiCommentList
css={css`
padding-bottom: 32px;
`}
>
{compact(
items.map((item, index) =>
!item.display.hide ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
EuiListGroupItem,
EuiLoadingSpinner,
EuiPanel,
EuiSpacer,
EuiText,
} from '@elastic/eui';
import { css } from '@emotion/css';
Expand All @@ -28,8 +29,16 @@ const titleClassName = css`
text-transform: uppercase;
`;

const panelClassName = css`
max-height: 100%;
`;

const overflowScrollClassName = css`
overflow-y: auto;
`;

const newChatButtonWrapperClassName = css`
padding-bottom: 5px;
padding-bottom: 2px;
`;

export function ConversationList({
Expand All @@ -49,14 +58,15 @@ export function ConversationList({
onClickDeleteConversation: (id: string) => void;
}) {
return (
<EuiPanel paddingSize="s" hasShadow={false}>
<EuiPanel paddingSize="s" hasShadow={false} className={panelClassName}>
<EuiFlexGroup direction="column" gutterSize="none" className={containerClassName}>
<EuiFlexItem grow>
<EuiFlexItem grow className={overflowScrollClassName}>
<EuiFlexGroup direction="column" gutterSize="xs">
<EuiFlexItem grow={false}>
<EuiPanel hasBorder={false} hasShadow={false} paddingSize="s">
<EuiFlexGroup direction="row" gutterSize="xs" alignItems="center">
<EuiFlexItem grow={false}>
<EuiSpacer size="s" />
<EuiText className={titleClassName} size="s">
<strong>
{i18n.translate('xpack.observabilityAiAssistant.conversationList.title', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import React from 'react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiIcon,
EuiLink,
EuiLoadingSpinner,
EuiPanel,
Expand Down Expand Up @@ -50,6 +51,7 @@ export function KnowledgeBaseCallout({ knowledgeBase }: { knowledgeBase: UseKnow
color = 'plain';
content = (
<EuiText size="xs" color="subdued">
<EuiIcon type="iInCircle" />{' '}
{i18n.translate('xpack.observabilityAiAssistant.poweredByModel', {
defaultMessage: 'Powered by {model}',
values: {
Expand Down Expand Up @@ -100,7 +102,13 @@ export function KnowledgeBaseCallout({ knowledgeBase }: { knowledgeBase: UseKnow
}

return (
<EuiPanel hasBorder={false} hasShadow={false} borderRadius="none" color={color} paddingSize="s">
<EuiPanel
hasBorder={false}
hasShadow={false}
borderRadius="none"
color={color}
paddingSize={knowledgeBase.status.value?.ready ? 'none' : 's'}
>
{content}
</EuiPanel>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export function ConnectorSelectorBase(props: ConnectorSelectorBaseProps) {
gutterSize="xs"
responsive={false}
>
<EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiSuperSelect
compressed
valueOfSelected={props.selectedConnector}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export function useConversation({
displayedMessages: Message[];
setDisplayedMessages: Dispatch<SetStateAction<Message[]>>;
save: (messages: Message[], handleRefreshConversations?: () => void) => Promise<Conversation>;
saveTitle: (
title: string,
handleRefreshConversations?: () => void
) => Promise<Conversation | void>;
} {
const service = useObservabilityAIAssistant();

Expand Down Expand Up @@ -144,5 +148,25 @@ export function useConversation({
throw err;
});
},
saveTitle: (title: string, handleRefreshConversations?: () => void) => {
if (conversationId) {
return service
.callApi('PUT /internal/observability_ai_assistant/conversation/{conversationId}/title', {
signal: null,
params: {
path: {
conversationId,
},
body: {
title,
},
},
})
.then(() => {
handleRefreshConversations?.();
});
}
return Promise.resolve();
},
};
}
Loading

0 comments on commit 54301ca

Please sign in to comment.