Skip to content

Commit

Permalink
Tweaks to prompt editor
Browse files Browse the repository at this point in the history
  • Loading branch information
CoenWarmer committed Dec 28, 2023
1 parent b93868e commit e963efa
Show file tree
Hide file tree
Showing 11 changed files with 86 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import type { UseGenAIConnectorsResult } from '../../hooks/use_genai_connectors'
import type { UseKnowledgeBaseResult } from '../../hooks/use_knowledge_base';
import { type Conversation, type Message, MessageRole } from '../../../common/types';
import { ChatHeader } from './chat_header';
import { ChatPromptEditor } from './chat_prompt_editor';
import { PromptEditor } from '../prompt_editor/prompt_editor';
import { ChatTimeline } from './chat_timeline';
import { Feedback } from '../feedback_buttons';
import { IncorrectLicensePanel } from './incorrect_license_panel';
Expand Down Expand Up @@ -141,6 +141,8 @@ export function ChatBody({
: '100%'};
`;

const [isEditing, setIsEditing] = useState(false);

const [stickToBottom, setStickToBottom] = useState(true);

const isAtBottom = (parent: HTMLElement) =>
Expand Down Expand Up @@ -214,7 +216,7 @@ export function ChatBody({
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiPanel hasBorder={false} hasShadow={false} paddingSize="m">
<ChatPromptEditor
<PromptEditor
hidden={connectors.loading || connectors.connectors?.length === 0}
loading={isLoading}
disabled
Expand Down Expand Up @@ -256,6 +258,7 @@ export function ChatBody({
currentUser={currentUser}
chatState={state}
hasConnector={!!connectors.connectors?.length}
onEditing={(editing) => setIsEditing(editing)}
onEdit={(editedMessage, newMessage) => {
const indexOf = messages.indexOf(editedMessage);
next(messages.slice(0, indexOf).concat(newMessage));
Expand Down Expand Up @@ -313,14 +316,14 @@ export function ChatBody({
color="subdued"
className={promptEditorContainerClassName}
>
<ChatPromptEditor
disabled={!connectors.selectedConnector || !hasCorrectLicense}
<PromptEditor
disabled={!connectors.selectedConnector || !hasCorrectLicense || isEditing}
hidden={connectors.loading || connectors.connectors?.length === 0}
loading={isLoading}
onChangeHeight={handleChangeHeight}
onSendTelemetry={(eventWithPayload) =>
sendEvent(chatService.analytics, eventWithPayload)
}
onChangeHeight={handleChangeHeight}
onSubmit={(message) => {
setStickToBottom(true);
return next(messages.concat(message));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const noPanelStyle = css`
export function ChatConsolidatedItems({
consolidatedItem,
onActionClick,
onEditing,
onEditSubmit,
onFeedback,
onRegenerate,
Expand All @@ -58,6 +59,7 @@ export function ChatConsolidatedItems({
}: {
consolidatedItem: ChatTimelineItem[];
onActionClick: ChatTimelineProps['onActionClick'];
onEditing: ChatTimelineProps['onEditing'];
onEditSubmit: ChatTimelineProps['onEdit'];
onFeedback: ChatTimelineProps['onFeedback'];
onRegenerate: ChatTimelineProps['onRegenerate'];
Expand Down Expand Up @@ -125,6 +127,7 @@ export function ChatConsolidatedItems({
key={index}
{...item}
onActionClick={onActionClick}
onEditing={onEditing}
onEditSubmit={(message) => onEditSubmit(item.message, message)}
onFeedbackClick={(feedback) => {
onFeedback(item.message, feedback);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import type { TelemetryEventTypeWithPayload } from '../../analytics';
export interface ChatItemProps extends Omit<ChatTimelineItem, 'message'> {
onActionClick: ChatActionClickHandler;
onEditSubmit: (message: Message) => void;
onEditing: (editing: boolean) => void;
onFeedbackClick: (feedback: Feedback) => void;
onRegenerateClick: () => void;
onSendTelemetry: (eventWithPayload: TelemetryEventTypeWithPayload) => void;
Expand Down Expand Up @@ -86,6 +87,7 @@ export function ChatItem({
loading,
title,
onActionClick,
onEditing,
onEditSubmit,
onFeedbackClick,
onRegenerateClick,
Expand Down Expand Up @@ -123,10 +125,13 @@ export function ChatItem({
setExpanded(true);
}
setEditing(!editing);

onEditing(!editing);
};

const handleInlineEditSubmit = (newMessage: Message) => {
handleToggleEdit();
onEditing(false);
return onEditSubmit(newMessage);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
*/

import React from 'react';
import { EuiPanel } from '@elastic/eui';
import { noop } from 'lodash';
import { css } from '@emotion/css';
import { EuiPanel } from '@elastic/eui';
import { MessageText } from '../message_panel/message_text';
import { ChatPromptEditor } from './chat_prompt_editor';
import { PromptEditor } from '../prompt_editor/prompt_editor';
import type { Message } from '../../../common';
import type { ChatActionClickHandler } from './types';
import type { TelemetryEventTypeWithPayload } from '../../analytics';
Expand Down Expand Up @@ -59,14 +60,14 @@ export function ChatItemContentInlinePromptEditor({
hasShadow={false}
className={editorContainerClassName}
>
<ChatPromptEditor
<PromptEditor
disabled={false}
hidden={false}
loading={false}
initialFunctionCall={functionCall}
initialContent={content}
initialRole={role}
onChangeHeight={() => {}}
onChangeHeight={noop}
onSubmit={onSubmit}
onSendTelemetry={onSendTelemetry}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ const defaultProps: ComponentProps<typeof Component> = {
}),
],
onActionClick: async () => {},
onEditing: () => {},
onEdit: async () => {},
onFeedback: () => {},
onRegenerate: () => {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export interface ChatTimelineProps {
chatState: ChatState;
currentUser?: Pick<AuthenticatedUser, 'full_name' | 'username'>;
startedFrom?: StartedFrom;
onEditing: (editing: boolean) => void;
onEdit: (message: Message, messageAfterEdit: Message) => void;
onFeedback: (message: Message, feedback: Feedback) => void;
onRegenerate: (message: Message) => void;
Expand All @@ -68,6 +69,7 @@ export function ChatTimeline({
hasConnector,
currentUser,
startedFrom,
onEditing,
onEdit,
onFeedback,
onRegenerate,
Expand Down Expand Up @@ -120,9 +122,10 @@ export function ChatTimeline({
key={index}
consolidatedItem={item}
onActionClick={onActionClick}
onEditing={onEditing}
onEditSubmit={onEdit}
onFeedback={onFeedback}
onRegenerate={onRegenerate}
onEditSubmit={onEdit}
onSendTelemetry={onSendTelemetry}
onStopGenerating={onStopGenerating}
/>
Expand All @@ -138,6 +141,7 @@ export function ChatTimeline({
onRegenerateClick={() => {
onRegenerate(item.message);
}}
onEditing={onEditing}
onEditSubmit={(message) => {
onEdit(item.message, message);
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ export function FunctionListPopover({
display="block"
>
<EuiButtonIcon
aria-label={i18n.translate(
'xpack.observabilityAiAssistant.functionListPopover.euiButtonIcon.selectAFunctionLabel',
{ defaultMessage: 'Select function' }
)}
data-test-subj="observabilityAiAssistantFunctionListPopoverButton"
disabled={disabled}
iconType={selectedFunctionName ? 'cross' : 'plusInCircle'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@

import React from 'react';
import { ComponentStory } from '@storybook/react';
import { ChatPromptEditor as Component, ChatPromptEditorProps } from './chat_prompt_editor';
import { PromptEditor as Component, PromptEditorProps } from './prompt_editor';
import { KibanaReactStorybookDecorator } from '../../utils/storybook_decorator';

/*
JSON Schema validation in the ChatPromptEditor compponent does not work
JSON Schema validation in the PromptEditor compponent does not work
when rendering the component from within Storybook.
*/
export default {
component: Component,
title: 'app/Molecules/ChatPromptEditor',
title: 'app/Molecules/PromptEditor',
argTypes: {},
parameters: {
backgrounds: {
Expand All @@ -28,11 +28,11 @@ export default {
decorators: [KibanaReactStorybookDecorator],
};

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

const defaultProps = {};

export const ChatPromptEditor = Template.bind({});
ChatPromptEditor.args = defaultProps;
export const PromptEditor = Template.bind({});
PromptEditor.args = defaultProps;
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,13 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiFocusTrap, keys } from '@elastic/eui';

import { MessageRole, type Message } from '../../../common';
import { FunctionListPopover } from './function_list_popover';

import { FunctionListPopover } from '../chat/function_list_popover';
import { TelemetryEventTypeWithPayload, TELEMETRY } from '../../analytics';
import { ChatPromptEditorFunction } from './chat_prompt_editor_function';
import { ChatPromptEditorPrompt } from './chat_prompt_editor_prompt';
import { PromptEditorFunction } from './prompt_editor_function';
import { PromptEditorNaturalLanguage } from './prompt_editor_natural_language';

export interface ChatPromptEditorProps {
export interface PromptEditorProps {
disabled: boolean;
hidden: boolean;
loading: boolean;
Expand All @@ -28,7 +26,7 @@ export interface ChatPromptEditorProps {
onSubmit: (message: Message) => void;
}

export function ChatPromptEditor({
export function PromptEditor({
disabled,
hidden,
loading,
Expand All @@ -38,7 +36,7 @@ export function ChatPromptEditor({
onChangeHeight,
onSendTelemetry,
onSubmit,
}: ChatPromptEditorProps) {
}: PromptEditorProps) {
const containerRef = useRef<HTMLDivElement>(null);

const isFocusTrapEnabled = Boolean(initialContent || initialFunctionCall);
Expand All @@ -47,6 +45,8 @@ export function ChatPromptEditor({
initialFunctionCall?.name ? 'function' : 'prompt'
);

const [hasFocus, setHasFocus] = useState(false);

const initialInnerMessage = initialRole
? {
role: initialRole,
Expand Down Expand Up @@ -113,9 +113,11 @@ export function ChatPromptEditor({
// Submit on Enter
useEffect(() => {
const keyboardListener = (event: KeyboardEvent) => {
if (!event.shiftKey && event.key === keys.ENTER && innerMessage) {
event.preventDefault();
handleSubmit();
if (innerMessage && !disabled && hasFocus) {
if (!event.shiftKey && event.key === keys.ENTER) {
event.preventDefault();
handleSubmit();
}
}
};

Expand All @@ -124,7 +126,7 @@ export function ChatPromptEditor({
return () => {
window.removeEventListener('keypress', keyboardListener);
};
}, [handleSubmit, innerMessage]);
}, [disabled, handleSubmit, hasFocus, innerMessage]);

useEffect(() => {
if (hidden) {
Expand All @@ -145,17 +147,21 @@ export function ChatPromptEditor({
</EuiFlexItem>
<EuiFlexItem>
{mode === 'function' && innerMessage?.function_call?.name ? (
<ChatPromptEditorFunction
<PromptEditorFunction
functionName={innerMessage.function_call.name}
functionPayload={innerMessage.function_call.arguments}
onChange={handleChangeMessageInner}
onFocus={() => setHasFocus(true)}
onBlur={() => setHasFocus(false)}
/>
) : (
<ChatPromptEditorPrompt
<PromptEditorNaturalLanguage
disabled={disabled}
prompt={innerMessage?.content}
onChange={handleChangeMessageInner}
onChangeHeight={onChangeHeight}
onFocus={() => setHasFocus(true)}
onBlur={() => setHasFocus(false)}
/>
)}
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,21 @@ export interface Props {
functionName: string;
functionPayload?: string;
onChange: (message: Message['message']) => void;
onFocus: () => void;
onBlur: () => void;
}

const functionNameClassName = css`
display: inline-block;
`;

export function ChatPromptEditorFunction({ functionName, functionPayload, onChange }: Props) {
export function PromptEditorFunction({
functionName,
functionPayload,
onChange,
onFocus,
onBlur,
}: Props) {
const [functionEditorLineCount, setFunctionEditorLineCount] = useState<number>(0);

const previousPayload = usePrevious(functionPayload);
Expand Down Expand Up @@ -72,6 +80,12 @@ export function ChatPromptEditorFunction({ functionName, functionPayload, onChan
}
}, [functionName, functionPayload, initialJsonString, onChange, previousPayload]);

useEffect(() => {
return () => {
onBlur();
};
}, [onBlur]);

return (
<EuiPanel paddingSize="none" hasShadow={false} hasBorder>
<EuiCode className={functionNameClassName}>{functionName}</EuiCode>
Expand All @@ -95,6 +109,7 @@ export function ChatPromptEditorFunction({ functionName, functionPayload, onChan
}}
editorDidMount={(editor) => {
editor.focus();
onFocus();
}}
options={{
accessibilitySupport: 'off',
Expand Down
Loading

0 comments on commit e963efa

Please sign in to comment.