Skip to content

Commit

Permalink
docs(misc): add "new chat" button to AI page
Browse files Browse the repository at this point in the history
  • Loading branch information
jaysoo committed Sep 13, 2023
1 parent 5056d6c commit 29b85ab
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 32 deletions.
8 changes: 6 additions & 2 deletions nx-dev/feature-ai/src/lib/error-message.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { type JSX, memo } from 'react';
import {
XCircleIcon,
ExclamationTriangleIcon,
XCircleIcon,
} from '@heroicons/react/24/outline';

export function ErrorMessage({ error }: { error: any }): JSX.Element {
function ErrorMessage({ error }: { error: any }): JSX.Element {
try {
if (error.message) {
error = JSON.parse(error.message);
Expand Down Expand Up @@ -57,3 +58,6 @@ export function ErrorMessage({ error }: { error: any }): JSX.Element {
);
}
}

const MemoErrorMessage = memo(ErrorMessage);
export { MemoErrorMessage as ErrorMessage };
54 changes: 33 additions & 21 deletions nx-dev/feature-ai/src/lib/feed-container.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { sendCustomEvent } from '@nx/nx-dev/feature-analytics';
import { RefObject, useEffect, useRef, useState } from 'react';
import { type JSX, RefObject, useEffect, useRef, useState } from 'react';
import { ErrorMessage } from './error-message';
import { Feed } from './feed/feed';
import { LoadingState } from './loading-state';
Expand All @@ -19,24 +19,35 @@ export function FeedContainer(): JSX.Element {
const [startedReply, setStartedReply] = useState(false);

const feedContainer: RefObject<HTMLDivElement> | undefined = useRef(null);
const { messages, input, handleInputChange, handleSubmit, isLoading } =
useChat({
api: '/api/query-ai-handler',
onError: (error) => {
setError(error);
},
onResponse: (_response) => {
setStartedReply(true);
sendCustomEvent('ai_query', 'ai', 'query', undefined, {
query: input,
});
setError(null);
},
onFinish: (response: Message) => {
setStartedReply(false);
storeQueryForUid(response.id, input);
},
});
const {
messages,
setMessages,
input,
handleInputChange,
handleSubmit,
isLoading,
} = useChat({
api: '/api/query-ai-handler',
onError: (error) => {
setError(error);
},
onResponse: (_response) => {
setStartedReply(true);
sendCustomEvent('ai_query', 'ai', 'query', undefined, {
query: input,
});
setError(null);
},
onFinish: (response: Message) => {
setStartedReply(false);
storeQueryForUid(response.id, input);
},
});

const handleNewChat = () => {
setMessages([]);
setError(null);
};

useEffect(() => {
if (feedContainer.current) {
Expand Down Expand Up @@ -86,8 +97,9 @@ export function FeedContainer(): JSX.Element {

<div className="sticky bottom-0 left-0 right-0 w-full pt-6 pb-4 bg-gradient-to-t from-white via-white dark:from-slate-900 dark:via-slate-900">
<Prompt
handleSubmit={handleSubmit}
handleInputChange={handleInputChange}
onSubmit={handleSubmit}
onInputChange={handleInputChange}
onNewChat={handleNewChat}
input={input}
isDisabled={isLoading}
/>
Expand Down
45 changes: 38 additions & 7 deletions nx-dev/feature-ai/src/lib/prompt.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import { ChangeEvent, FormEvent, useEffect, useRef } from 'react';
import { PaperAirplaneIcon } from '@heroicons/react/24/outline';
import { PaperAirplaneIcon, PlusIcon } from '@heroicons/react/24/outline';
import { Button } from '@nx/nx-dev/ui-common';
import Textarea from 'react-textarea-autosize';
import { ChatRequestOptions } from 'ai';
import { cx } from '@nx/nx-dev/ui-primitives';

export function Prompt({
isDisabled,
handleSubmit,
handleInputChange,
onSubmit,
onInputChange,
onNewChat,
input,
}: {
isDisabled: boolean;
handleSubmit: (
onSubmit: (
e: FormEvent<HTMLFormElement>,
chatRequestOptions?: ChatRequestOptions | undefined
) => void;
handleInputChange: (
onInputChange: (
e: ChangeEvent<HTMLTextAreaElement> | ChangeEvent<HTMLInputElement>
) => void;
onNewChat: () => void;
input: string;
}) {
const formRef = useRef<HTMLFormElement>(null);
Expand All @@ -32,9 +35,37 @@ export function Prompt({
return (
<form
ref={formRef}
onSubmit={handleSubmit}
onSubmit={(event) => {
if (inputRef.current?.value.trim()) onSubmit(event);
else event.preventDefault();
}}
className="relative flex gap-2 max-w-2xl mx-auto py-0 px-2 shadow-lg rounded-md border border-slate-300 bg-white dark:border-slate-900 dark:bg-slate-700"
>
<div className="flex pb-2 relative group">
<Button
variant="secondary"
size="small"
rounded="full"
className="self-end w-12 h-12 disabled:cursor-not-allowed"
onClick={onNewChat}
>
<div hidden className="sr-only">
New chat
</div>
<PlusIcon aria-hidden="true" className="h-5 w-5" />
</Button>
<span
aria-hidden="true"
className={cx(
'opacity-0 group-hover:opacity-100 transition-opacity delay-75',
'w-max py-1.5 px-3 rounded-md border shadow-md',
'text-sm bg-white text-slate-700 border-slate-300 dark:bg-slate-900 dark:text-slate-200 dark:border-slate-300',
'absolute top-0 left-1/2 -translate-x-1/2 -translate-y-full'
)}
>
New chat
</span>
</div>
<div className="overflow-y-auto w-full h-full max-h-[300px]">
<Textarea
onKeyDown={(event) => {
Expand All @@ -49,7 +80,7 @@ export function Prompt({
}}
ref={inputRef}
value={input}
onChange={handleInputChange}
onChange={onInputChange}
id="query-prompt"
name="query"
disabled={isDisabled}
Expand Down
9 changes: 7 additions & 2 deletions nx-dev/ui-common/src/lib/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type AllowedSizes = 'large' | 'default' | 'small';
interface ButtonProps {
variant?: AllowedVariants;
size?: AllowedSizes;
rounded?: 'full' | 'default';
children: ReactNode | ReactNode[];
}

Expand Down Expand Up @@ -45,12 +46,15 @@ function ButtonInner({
children,
variant = 'primary',
size = 'default',
rounded = 'default',
}: ButtonProps): JSX.Element {
return (
<>
<span
className={cx(
'flex h-full w-full items-center justify-center whitespace-nowrap rounded-md border border-transparent font-medium shadow-sm transition',
'flex h-full w-full items-center justify-center whitespace-nowrap',
rounded === 'full' ? 'rounded-full' : 'rounded-md',
'border border-transparent font-medium shadow-sm transition',
variantStyles[variant],
sizes[size]
)}
Expand All @@ -69,11 +73,12 @@ export function Button({
className = '',
variant = 'primary',
size = 'large',
rounded = 'default',
...props
}: ButtonProps & JSX.IntrinsicElements['button']): JSX.Element {
return (
<button {...props} className={getLayoutClassName(className)}>
<ButtonInner variant={variant} size={size}>
<ButtonInner variant={variant} size={size} rounded={rounded}>
{children}
</ButtonInner>
</button>
Expand Down

0 comments on commit 29b85ab

Please sign in to comment.