Skip to content

Commit

Permalink
feat(nx-dev): use textarea for prompts and show a better "no results"…
Browse files Browse the repository at this point in the history
… error
  • Loading branch information
jaysoo committed Aug 23, 2023
1 parent fca4686 commit 2e2f711
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 62 deletions.
56 changes: 43 additions & 13 deletions nx-dev/feature-ai/src/lib/error-message.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,49 @@
import { XCircleIcon } from '@heroicons/react/24/outline';
import {
XCircleIcon,
ExclamationTriangleIcon,
} from '@heroicons/react/24/outline';

export function ErrorMessage({ error }: { error: any }): JSX.Element {
return (
<div className="rounded-md bg-red-50 p-4">
<div className="flex">
<div className="flex-shrink-0">
<XCircleIcon className="h-5 w-5 text-red-400" aria-hidden="true" />
if (error.data.no_results) {
return (
<div className="rounded-md bg-yellow-50 p-4">
<div className="flex">
<div className="flex-shrink-0">
<ExclamationTriangleIcon
className="h-5 w-5 text-yellow-500"
aria-hidden="true"
/>
</div>
<div className="ml-3">
<h3 className="text-sm font-medium text-yellow-800">
No results found
</h3>
<div className="mt-2 text-sm text-yellow-700">
Sorry, I don't know how to help with that. You can visit the{' '}
<a href="https://nx.dev/getting-started/intro" className="underline">
Nx documentation
</a>{' '}
for more info.
</div>
</div>
</div>
<div className="ml-3">
<h3 className="text-sm font-medium text-red-800">
Oopsies! I encountered an error
</h3>
<div className="mt-2 text-sm text-red-700">{error['message']}</div>
</div>
);
} else {
return (
<div className="rounded-md bg-red-50 p-4">
<div className="flex">
<div className="flex-shrink-0">
<XCircleIcon className="h-5 w-5 text-red-400" aria-hidden="true" />
</div>
<div className="ml-3">
<h3 className="text-sm font-medium text-red-800">
Oopsies! I encountered an error
</h3>
<div className="mt-2 text-sm text-red-700">{error['message']}</div>
</div>
</div>
</div>
</div>
);
);
}
}
16 changes: 4 additions & 12 deletions nx-dev/feature-ai/src/lib/feed-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
ChatItem,
getProcessedHistory,
queryAi,
resetHistory,
sendFeedbackAnalytics,
sendQueryAnalytics,
} from '@nx/nx-dev/data-access-ai';
Expand All @@ -12,7 +11,6 @@ import { ErrorMessage } from './error-message';
import { Feed } from './feed/feed';
import { LoadingState } from './loading-state';
import { Prompt } from './prompt';
import { WarningMessage } from './sidebar/warning-message';
import { formatMarkdownSources } from './utils';

interface LastQueryMetadata {
Expand All @@ -33,7 +31,7 @@ const assistantWelcome: ChatItem = {

export function FeedContainer(): JSX.Element {
const [chatHistory, setChatHistory] = useState<ChatItem[]>([]);
const [hasError, setHasError] = useState<any | null>(null);
const [queryError, setQueryError] = useState<any | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [lastQueryMetadata, setLastQueryMetadata] =
useState<LastQueryMetadata | null>(null);
Expand All @@ -54,7 +52,7 @@ export function FeedContainer(): JSX.Element {
currentHistory.push({ role: 'user', content: query });

setIsLoading(true);
setHasError(null);
setQueryError(null);

try {
const lastAnswerChatItem =
Expand Down Expand Up @@ -94,7 +92,7 @@ export function FeedContainer(): JSX.Element {
...aiResponse.usage,
});
} catch (error: any) {
setHasError(error);
setQueryError(error);
}

setIsLoading(false);
Expand Down Expand Up @@ -122,12 +120,6 @@ export function FeedContainer(): JSX.Element {
});
};

const handleReset = () => {
resetHistory();
setChatHistory([]);
setHasError(null);
};

return (
<>
{/*WRAPPER*/}
Expand Down Expand Up @@ -158,7 +150,7 @@ export function FeedContainer(): JSX.Element {
/>

{isLoading && <LoadingState />}
{hasError && <ErrorMessage error={hasError} />}
{queryError && <ErrorMessage error={queryError} />}

<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
Expand Down
73 changes: 52 additions & 21 deletions nx-dev/feature-ai/src/lib/prompt.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { useEffect, useRef, useState } from 'react';
import { PaperAirplaneIcon } from '@heroicons/react/24/outline';
import { Button } from '@nx/nx-dev/ui-common';
import Textarea from 'react-textarea-autosize';

export function Prompt({
isDisabled,
Expand All @@ -8,35 +10,64 @@ export function Prompt({
isDisabled: boolean;
handleSubmit: (query: string) => void;
}) {
const formRef = useRef<HTMLFormElement>(null);
const inputRef = useRef<HTMLTextAreaElement>(null);
const [inputValue, setInputValue] = useState<string>('');

useEffect(() => {
if (inputRef.current) {
inputRef.current.focus();
}
}, []);

return (
<form
ref={formRef}
onSubmit={(event) => {
event.preventDefault();
handleSubmit((event.target as any).query.value);
if (!inputValue?.trim()) return;
handleSubmit(inputValue);
setInputValue('');
event.currentTarget.reset();
}}
className="relative flex gap-4 max-w-xl mx-auto py-2 px-4 shadow-lg rounded-md border border-slate-300 bg-white dark:border-slate-900 dark:bg-slate-700"
>
<input
id="query-prompt"
name="query"
disabled={isDisabled}
className="p-0 flex flex-grow text-sm placeholder-slate-500 transition bg-transparent focus:placeholder-slate-400 dark:focus:placeholder-slate-300 dark:text-white focus:outline-none focus:ring-0 border-none disabled:cursor-not-allowed"
placeholder="How does caching work?"
type="text"
/>
<Button
variant="primary"
size="small"
type="submit"
disabled={isDisabled}
className="disabled:cursor-not-allowed"
>
<div hidden className="sr-only">
Ask
</div>
<PaperAirplaneIcon aria-hidden="true" className="h-5 w-5" />
</Button>
<div className="overflow-y-auto w-full h-full max-h-[300px]">
<Textarea
onKeyDown={(event) => {
if (
event.key === 'Enter' &&
!event.shiftKey &&
!event.nativeEvent.isComposing
) {
formRef.current?.requestSubmit();
event.preventDefault();
}
}}
ref={inputRef}
onChange={(event) => setInputValue(event.target.value)}
id="query-prompt"
name="query"
disabled={isDisabled}
className="w-full p-0 resize-none bg-transparent text-sm placeholder-slate-500 px-4 py-[1.3rem] focus-within:outline-none focus:placeholder-slate-400 dark:focus:placeholder-slate-300 dark:text-white focus:outline-none focus:ring-0 border-none disabled:cursor-not-allowed"
placeholder="How does caching work?"
rows={1}
/>
</div>
<div className="absolute right-0 top-4 sm:right-4">
<Button
variant="primary"
size="small"
type="submit"
disabled={isDisabled}
className="w-12 h-12 disabled:cursor-not-allowed"
>
<div hidden className="sr-only">
Ask
</div>
<PaperAirplaneIcon aria-hidden="true" className="h-5 w-5" />
</Button>
</div>
</form>
);
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@
"react-redux": "8.0.5",
"react-refresh": "^0.10.0",
"react-router-dom": "^6.11.2",
"react-textarea-autosize": "^8.3.0",
"regenerator-runtime": "0.13.7",
"resolve.exports": "1.1.0",
"rollup": "^2.56.2",
Expand Down
Loading

0 comments on commit 2e2f711

Please sign in to comment.