Skip to content

Commit

Permalink
refactor AIChat for better readability
Browse files Browse the repository at this point in the history
  • Loading branch information
jsartisan committed Oct 11, 2024
1 parent 906b65c commit 72dabf2
Show file tree
Hide file tree
Showing 11 changed files with 186 additions and 200 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { Avatar, Button, ChatInput, Flex, Icon, Text } from "@appsmith/wds";
import type { ForwardedRef } from "react";
import React, { forwardRef } from "react";
import { ChatDescriptionModal } from "./ChatDescriptionModal";
import styles from "./styles.module.css";
import { ThreadMessage } from "./ThreadMessage";
import type { AIChatProps, ChatMessage } from "./types";

const MIN_PROMPT_LENGTH = 3;
const LOGO =
"https://app.appsmith.com/static/media/appsmith_logo_square.3867b1959653dabff8dc.png";
import styles from "./styles.module.css";
import { ChatHeader } from "./ChatHeader";
import { ChatThread } from "./ChatThread";
import type { AIChatProps } from "./types";
import { ChatInputSection } from "./ChatInputSection";

const _AIChat = (props: AIChatProps, ref: ForwardedRef<HTMLDivElement>) => {
const {
Expand All @@ -25,81 +22,28 @@ const _AIChat = (props: AIChatProps, ref: ForwardedRef<HTMLDivElement>) => {
username,
...rest
} = props;
const [isChatDescriptionModalOpen, setIsChatDescriptionModalOpen] =
React.useState(false);

return (
<div className={styles.root} ref={ref} {...rest}>
<ChatDescriptionModal
isOpen={isChatDescriptionModalOpen}
setOpen={setIsChatDescriptionModalOpen}
>
{chatDescription}
</ChatDescriptionModal>

<div className={styles.header}>
<Flex alignItems="center" gap="spacing-2">
<Flex alignItems="center" gap="spacing-3">
<Avatar label="Appsmith AI" size="large" src={LOGO} />
<Text fontWeight={600} size="subtitle">
{chatTitle}
</Text>
</Flex>
<Button
icon="info-square-rounded"
onPress={() => setIsChatDescriptionModalOpen(true)}
variant="ghost"
/>
</Flex>

<Flex alignItems="center" gap="spacing-2">
<Avatar label={username} />
<Text data-testid="t--aichat-username" size="body">
{username}
</Text>
</Flex>
</div>

<ul className={styles.thread} data-testid="t--aichat-thread">
{thread.map((message: ChatMessage) => (
<ThreadMessage
{...message}
key={message.id}
onApplyAssistantSuggestion={onApplyAssistantSuggestion}
username={username}
/>
))}
</ul>

<Flex
direction="column"
gap="spacing-3"
paddingBottom="spacing-4"
paddingLeft="spacing-6"
paddingRight="spacing-6"
paddingTop="spacing-4"
>
<ChatInput
isLoading={isWaitingForResponse}
isSubmitDisabled={prompt.length < MIN_PROMPT_LENGTH}
onChange={onPromptChange}
onSubmit={onSubmit}
placeholder={promptInputPlaceholder}
value={prompt}
/>
<Flex
alignItems="center"
flexGrow={1}
gap="spacing-1"
justifyContent="center"
>
<Icon name="alert-circle" size="small" />
<Text color="neutral" size="caption" textAlign="center">
LLM assistant can make mistakes. Answers should be verified before
they are trusted.
</Text>
</Flex>
</Flex>
<ChatHeader
chatDescription={chatDescription}
chatTitle={chatTitle}
username={username}
/>

<ChatThread
onApplyAssistantSuggestion={onApplyAssistantSuggestion}
thread={thread}
username={username}
/>

<ChatInputSection
isWaitingForResponse={isWaitingForResponse}
onPromptChange={onPromptChange}
onSubmit={onSubmit}
prompt={prompt}
promptInputPlaceholder={promptInputPlaceholder}
/>
</div>
);
};
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from "react";
import styles from "./styles.module.css";
import {
Avatar,
Button,
Flex,
Modal,
ModalBody,
ModalContent,
ModalHeader,
Text,
} from "@appsmith/wds";

// this value might come from props in future. So keeping a temporary value here.
const LOGO =
"https://app.appsmith.com/static/media/appsmith_logo_square.3867b1959653dabff8dc.png";

export const ChatHeader: React.FC<{
chatTitle?: string;
username: string;
chatDescription?: string;
}> = ({ chatDescription, chatTitle, username }) => {
const [isChatDescriptionModalOpen, setIsChatDescriptionModalOpen] =
React.useState(false);

return (
<>
<div className={styles.header}>
<Flex alignItems="center" gap="spacing-2">
<Flex alignItems="center" gap="spacing-3">
<Avatar label="Appsmith AI" size="large" src={LOGO} />
<Text fontWeight={600} size="subtitle">
{chatTitle}
</Text>
</Flex>
<Button
icon="info-square-rounded"
onPress={() => setIsChatDescriptionModalOpen(true)}
variant="ghost"
/>
</Flex>
<Flex alignItems="center" gap="spacing-2">
<Avatar label={username} />
<Text data-testid="t--aichat-username" size="body">
{username}
</Text>
</Flex>
</div>

<Modal
isOpen={isChatDescriptionModalOpen}
setOpen={setIsChatDescriptionModalOpen}
>
<ModalContent>
<ModalHeader title="Information about the bot" />
<ModalBody>{chatDescription}</ModalBody>
</ModalContent>
</Modal>
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from "react";
import { Flex, ChatInput, Icon, Text } from "@appsmith/wds";

const MIN_PROMPT_LENGTH = 3;

export const ChatInputSection: React.FC<{
isWaitingForResponse: boolean;
prompt: string;
promptInputPlaceholder?: string;
onPromptChange: (value: string) => void;
onSubmit?: () => void;
}> = ({
isWaitingForResponse,
onPromptChange,
onSubmit,
prompt,
promptInputPlaceholder,
}) => (
<Flex
direction="column"
gap="spacing-3"
paddingBottom="spacing-4"
paddingLeft="spacing-6"
paddingRight="spacing-6"
paddingTop="spacing-4"
>
<ChatInput
isLoading={isWaitingForResponse}
isSubmitDisabled={prompt.length < MIN_PROMPT_LENGTH}
onChange={onPromptChange}
onSubmit={onSubmit}
placeholder={promptInputPlaceholder}
value={prompt}
/>
<Flex
alignItems="center"
flexGrow={1}
gap="spacing-1"
justifyContent="center"
>
<Icon name="alert-circle" size="small" />
<Text color="neutral" size="caption" textAlign="center">
LLM assistant can make mistakes. Answers should be verified before they
are trusted.
</Text>
</Flex>
</Flex>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from "react";
import { Avatar, Flex, Markdown } from "@appsmith/wds";

import styles from "./styles.module.css";
import type { ChatMessage } from "./types";
import { AssistantSuggestionButton } from "./AssistantSuggestionButton";

export const ChatThread: React.FC<{
thread: ChatMessage[];
onApplyAssistantSuggestion?: (suggestion: string) => void;
username: string;
}> = ({ onApplyAssistantSuggestion, thread, username }) => (
<Flex direction="column" gap="spacing-3" padding="spacing-6">
{thread.map((message: ChatMessage) => {
const { content, isAssistant, promptSuggestions = [] } = message;

return (
<Flex direction={isAssistant ? "row" : "row-reverse"} key={message.id}>
{isAssistant && (
<div>
<Markdown>{content}</Markdown>

{promptSuggestions.length > 0 && (
<Flex
className={styles.suggestions}
gap="spacing-5"
paddingTop="spacing-4"
wrap="wrap"
>
{promptSuggestions.map((suggestion) => (
<AssistantSuggestionButton
key={suggestion}
// eslint-disable-next-line react-perf/jsx-no-new-function-as-prop
onPress={() => onApplyAssistantSuggestion?.(suggestion)}
>
{suggestion}
</AssistantSuggestionButton>
))}
</Flex>
)}
</div>
)}
{!isAssistant && (
<Flex direction="row-reverse" gap="spacing-3">
<Avatar label={username} />
<div>{content}</div>
</Flex>
)}
</Flex>
);
})}
</Flex>
);

This file was deleted.

This file was deleted.

Loading

0 comments on commit 72dabf2

Please sign in to comment.