Skip to content

Commit

Permalink
Merge pull request elastic#12 from CoenWarmer/storybook
Browse files Browse the repository at this point in the history
  • Loading branch information
CoenWarmer committed Jul 26, 2023
2 parents 27f224a + 3cb27a5 commit c9753e5
Show file tree
Hide file tree
Showing 10 changed files with 381 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { ComponentStory } from '@storybook/react';
import { ChatFlyout as Component, ChatFlyoutProps } from './chat_flyout';

export default {
component: Component,
title: 'app/Molecules/ChatFlyout',
argTypes: {},
};

const Template: ComponentStory<typeof Component> = (props: ChatFlyoutProps) => {
return <Component {...props} />;
};

const defaultProps = {};

export const ChatFlyout = Template.bind({});
ChatFlyout.args = defaultProps;
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* 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, { useState } from 'react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiFlyout,
EuiFlyoutBody,
EuiFlyoutFooter,
EuiFlyoutHeader,
EuiTitle,
} from '@elastic/eui';
import { euiThemeVars } from '@kbn/ui-theme';
import { useChatConversation } from '../../hooks/use_chat_conversation';
import { ChatTimeline } from './chat_timeline';
import { ChatPromptEditor } from './chat_prompt_editor';
import { AssistantAvatar } from '../assistant_avatar';

export interface ChatFlyoutProps {
conversationId?: string;
}

export function ChatFlyout({ conversationId }: ChatFlyoutProps) {
const { title, messages } = useChatConversation({ conversationId });

const [isOpen, setIsOpen] = useState(true);

const handleSubmit = (prompt: string) => {};

return isOpen ? (
<EuiFlyout onClose={() => setIsOpen(false)} size="m">
<EuiFlyoutHeader hasBorder>
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<AssistantAvatar size="m" />
</EuiFlexItem>
<EuiFlexItem>
<EuiTitle size="m">
<h2>{title}</h2>
</EuiTitle>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlyoutHeader>

<EuiFlyoutBody>
<ChatTimeline messages={messages} />
</EuiFlyoutBody>

<EuiFlyoutFooter
css={{ borderTop: `solid 1px ${euiThemeVars.euiBorderColor}`, background: '#fff' }}
>
<ChatPromptEditor onSubmitPrompt={handleSubmit} />
</EuiFlyoutFooter>
</EuiFlyout>
) : null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,12 @@ export function ChatItem({
anchorPosition="downLeft"
button={
<EuiButtonIcon
aria-label={i18n.translate('xpack.observabilityAiAssistant.insight.actions', {
defaultMessage: 'Actions',
})}
aria-label={i18n.translate(
'xpack.observabilityAiAssistant.chatTimeline.actions',
{
defaultMessage: 'Actions',
}
)}
color="text"
display="empty"
iconType="boxesHorizontal"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export function ChatItemControls({ role, onFeedbackClick, onRegenerateClick }: C
<EuiSpacer size="m" />
<EuiHorizontalRule margin="none" />
<EuiSpacer size="s" />

<EuiFlexGroup>
<EuiFlexItem>
{canReceiveFeedback ? <FeedbackButtons onClickFeedback={onFeedbackClick} /> : null}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { ComponentStory } from '@storybook/react';
import { ChatPromptEditor as Component, ChatPromptEditorProps } from './chat_prompt_editor';

export default {
component: Component,
title: 'app/Molecules/ChatPromptEditor',
argTypes: {},
};

const Template: ComponentStory<typeof Component> = (props: ChatPromptEditorProps) => {
return <Component {...props} />;
};

const defaultProps = {};

export const ChatPromptEditor = Template.bind({});
ChatPromptEditor.args = defaultProps;
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* 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, { useState } from 'react';
import {
EuiButtonIcon,
EuiContextMenuItem,
EuiContextMenuPanel,
EuiFieldText,
EuiFlexGroup,
EuiFlexItem,
EuiPopover,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useFunctions, Func } from '../../hooks/use_functions';

export interface ChatPromptEditorProps {
onSubmitPrompt: (prompt: string) => void;
}

export function ChatPromptEditor({ onSubmitPrompt }: ChatPromptEditorProps) {
const functions = useFunctions();

const [prompt, setPrompt] = useState('');
const [isFunctionListOpen, setIsFunctionListOpen] = useState(false);

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setPrompt(event.currentTarget.value);
};

const handleSubmit = () => {
onSubmitPrompt(prompt);
};

const handleClickFunctionList = () => {
setIsFunctionListOpen(!isFunctionListOpen);
};

const handleSelectFunction = (func: Func) => {
setIsFunctionListOpen(false);
};

return (
<EuiFlexGroup gutterSize="m">
<EuiFlexItem grow={false}>
<EuiPopover
anchorPosition="downLeft"
button={
<EuiButtonIcon
display="base"
iconType="function"
size="m"
onClick={handleClickFunctionList}
/>
}
closePopover={handleClickFunctionList}
panelPaddingSize="s"
isOpen={isFunctionListOpen}
>
<EuiContextMenuPanel
size="s"
items={functions.map((func) => (
<EuiContextMenuItem key={func.id} onClick={() => handleSelectFunction(func)}>
{func.function_name}
</EuiContextMenuItem>
))}
/>
</EuiPopover>
</EuiFlexItem>
<EuiFlexItem grow>
<EuiFieldText
fullWidth
value={prompt}
placeholder={i18n.translate('xpack.observabilityAiAssistant.prompt.placeholder', {
defaultMessage: 'Press ‘space’ or ‘$’ for function recommendations',
})}
onChange={handleChange}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonIcon
disabled={!prompt}
display={prompt ? 'fill' : 'base'}
iconType="kqlFunction"
size="m"
onClick={handleSubmit}
/>
</EuiFlexItem>
</EuiFlexGroup>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* 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 { Message } from '../../../common';
import {
buildAssistantInnerMessage,
buildElasticInnerMessage,
buildMessage,
buildSystemInnerMessage,
buildUserInnerMessage,
} from '../../utils/builders';

interface UseChatConversationProps {
conversationId?: string;
}

export function useChatConversation({ conversationId }: UseChatConversationProps): {
title: string;
messages: Message[];
} {
const currentDate = new Date();

return {
title: 'Event name',
messages: [
buildMessage({
'@timestamp': String(new Date(currentDate.getTime())),
message: buildSystemInnerMessage(),
}),
buildMessage({
'@timestamp': String(new Date(currentDate.getTime() + 1000)),
message: buildUserInnerMessage(),
}),
buildMessage({
'@timestamp': String(new Date(currentDate.getTime() + 2000)),
message: buildAssistantInnerMessage({
content: `In computer programming and mathematics, a function is a fundamental concept that represents a relationship between input values and output values. It takes one or more input values (also known as arguments or parameters) and processes them to produce a result, which is the output of the function. The input values are passed to the function, and the function performs a specific set of operations or calculations on those inputs to produce the desired output.
A function is often defined with a name, which serves as an identifier to call and use the function in the code. It can be thought of as a reusable block of code that can be executed whenever needed, and it helps in organizing code and making it more modular and maintainable.`,
}),
}),
buildMessage({
'@timestamp': String(new Date(currentDate.getTime() + 3000)),
message: buildUserInnerMessage({ content: 'How does it work?' }),
}),
buildMessage({
'@timestamp': String(new Date(currentDate.getTime() + 4000)),
message: buildElasticInnerMessage({
content: `The way functions work depends on whether we are talking about mathematical functions or programming functions. Let's explore both:
Mathematical Functions:
In mathematics, a function maps input values to corresponding output values based on a specific rule or expression. The general process of how a mathematical function works can be summarized as follows:
Step 1: Input - You provide an input value to the function, denoted as 'x' in the notation f(x). This value represents the independent variable.
Step 2: Processing - The function takes the input value and applies a specific rule or algorithm to it. This rule is defined by the function itself and varies depending on the function's expression.
Step 3: Output - After processing the input, the function produces an output value, denoted as 'f(x)' or 'y'. This output represents the dependent variable and is the result of applying the function's rule to the input.
Step 4: Uniqueness - A well-defined mathematical function ensures that each input value corresponds to exactly one output value. In other words, the function should yield the same output for the same input whenever it is called.`,
}),
}),
],
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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.
*/

interface FuncParameters {
name: string;
type: 'string' | 'int' | 'boolean' | 'object';
description: string;
}

export interface Func {
id: string;
function_name: string;
parameters: FuncParameters[];
}

export function useFunctions(): Func[] {
return [
{
id: '1',
function_name: 'get_service_summary',
parameters: [
{
name: 'service',
type: 'string',
description: 'The service',
},
],
},
{
id: '2',
function_name: 'get_apm_chart',
parameters: [],
},
{
id: '3',
function_name: 'get_dependencies',
parameters: [
{
name: 'service',
type: 'string',
description: 'The service',
},
],
},
{
id: '4',
function_name: 'get_correlation_values',
parameters: [],
},
{
id: '4',
function_name: 'get_error',
parameters: [],
},
];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* 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 { Message } from '../../common';

interface UseChatConversationProps {
conversationId?: string;
}

export function useChatConversation({ conversationId }: UseChatConversationProps): {
title: string;
messages: Message[];
} {
return { title: '', messages: [] };
}
Loading

0 comments on commit c9753e5

Please sign in to comment.