diff --git a/app/client/jest.config.js b/app/client/jest.config.js index abe29d26d8d..bc9bc713c12 100644 --- a/app/client/jest.config.js +++ b/app/client/jest.config.js @@ -5,7 +5,7 @@ const LOG_LEVELS = ["debug", "error"]; const CONFIG_LOG_LEVEL_INDEX = 1; module.exports = { - setupFiles: ["jest-canvas-mock"], + setupFiles: ["jest-canvas-mock", "/test/__mocks__/reactMarkdown.tsx"], roots: ["/src"], transform: { "^.+\\.(png|js|ts|tsx)$": "ts-jest", diff --git a/app/client/package.json b/app/client/package.json index 9ce6628afc7..a8dbd768511 100644 --- a/app/client/package.json +++ b/app/client/package.json @@ -161,6 +161,7 @@ "nanoid": "^2.0.4", "node-forge": "^1.3.0", "object-hash": "^3.0.0", + "openai": "^4.64.0", "path-to-regexp": "^6.3.0", "popper.js": "^1.15.0", "prismjs": "^1.27.0", diff --git a/app/client/packages/design-system/widgets/jest.config.js b/app/client/packages/design-system/widgets/jest.config.js index 59574a2a95b..08272cd0c57 100644 --- a/app/client/packages/design-system/widgets/jest.config.js +++ b/app/client/packages/design-system/widgets/jest.config.js @@ -1,6 +1,7 @@ module.exports = { preset: "ts-jest", roots: ["/src"], + setupFiles: ["../../../test/__mocks__/reactMarkdown.tsx"], testEnvironment: "jsdom", moduleNameMapper: { "\\.(css)$": "../../../test/__mocks__/styleMock.js", diff --git a/app/client/packages/design-system/widgets/package.json b/app/client/packages/design-system/widgets/package.json index d1069bce6cb..12607a4be39 100644 --- a/app/client/packages/design-system/widgets/package.json +++ b/app/client/packages/design-system/widgets/package.json @@ -26,10 +26,13 @@ "@tabler/icons-react": "^3.10.0", "clsx": "^2.0.0", "lodash": "*", - "react-aria-components": "^1.2.1" + "react-aria-components": "^1.2.1", + "react-markdown": "^9.0.1", + "react-syntax-highlighter": "^15.5.0" }, "devDependencies": { "@types/fs-extra": "^11.0.4", + "@types/react-syntax-highlighter": "^15.5.13", "eslint-plugin-storybook": "^0.6.10" }, "peerDependencies": { diff --git a/app/client/packages/design-system/widgets/src/components/AIChat/index.ts b/app/client/packages/design-system/widgets/src/components/AIChat/index.ts new file mode 100644 index 00000000000..3bd16e178a0 --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/AIChat/index.ts @@ -0,0 +1 @@ +export * from "./src"; diff --git a/app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx b/app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx new file mode 100644 index 00000000000..3a7c0f75596 --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx @@ -0,0 +1,85 @@ +import { Button, Spinner, Text, TextArea } from "@appsmith/wds"; +import type { FormEvent, ForwardedRef, KeyboardEvent } from "react"; +import React, { forwardRef, useCallback } from "react"; +import { ChatTitle } from "./ChatTitle"; +import styles from "./styles.module.css"; +import { ThreadMessage } from "./ThreadMessage"; +import type { AIChatProps, ChatMessage } from "./types"; +import { UserAvatar } from "./UserAvatar"; + +const MIN_PROMPT_LENGTH = 3; + +const _AIChat = (props: AIChatProps, ref: ForwardedRef) => { + const { + // assistantName, + chatTitle, + description, + isWaitingForResponse = false, + onPromptChange, + onSubmit, + prompt, + promptInputPlaceholder, + thread, + username, + ...rest + } = props; + + const handleFormSubmit = useCallback( + (event: FormEvent) => { + event.preventDefault(); + onSubmit?.(); + }, + [onSubmit], + ); + + const handlePromptInputKeyDown = useCallback( + (event: KeyboardEvent) => { + if (event.key === "Enter" && event.shiftKey) { + event.preventDefault(); + onSubmit?.(); + } + }, + [onSubmit], + ); + + return ( +
+
+ {chatTitle != null && } + + {description ?? {description}} +
+ + {username} +
+
+ +
    + {thread.map((message: ChatMessage) => ( + + ))} + + {isWaitingForResponse && ( +
  • + +
  • + )} +
+ +
+