feat: init AI chat widget (#36610)
## Description Fixes #36541 > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!WARNING] > Tests have not run on the HEAD c4a6e25abc716cc6a54e612a3800ca95079ba8a0 yet > <hr>Thu, 03 Oct 2024 11:06:19 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced the WDS AI Chat Widget for interactive chat experiences using OpenAI. - Added the AIChat component for enhanced chat functionality. - Expanded the collection of available widgets with the new WDS AI Chat Widget. - Introduced the ThreadMessage component for structured message rendering in the chat interface. - Added UserAvatar and ChatTitle components for improved user interaction and display. - Introduced new icons and thumbnails for AI Chat and Date Picker to enhance visual representation. - **Bug Fixes** - Resolved issues related to widget integration within the existing framework. - **Documentation** - Updated configuration files to enhance modularity and organization. - Expanded documentation to include new icons and thumbnails. - **Chores** - Added the OpenAI, React Markdown, and React Syntax Highlighter dependencies for improved functionality. - Introduced a new type declaration dependency for better type support. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Valera Melnikov <valera@appsmith.com> Co-authored-by: saiprabhu-dandanayak <saiprabhu.dandanayak@zemosolabs.com> Co-authored-by: Rudraprasad Das <rudra@appsmith.com> Co-authored-by: Abhishek Pandey <66054987+a6hishekpandey@users.noreply.github.com> Co-authored-by: NandanAnantharamu <67676905+NandanAnantharamu@users.noreply.github.com> Co-authored-by: “NandanAnantharamu” <“nandan@thinkify.io”> Co-authored-by: Anagh Hegde <anagh.hv@gmail.com> Co-authored-by: Abhijeet <abhi.nagarnaik@gmail.com> Co-authored-by: Abhijeet <41686026+abhvsn@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: albinAppsmith <87797149+albinAppsmith@users.noreply.github.com> Co-authored-by: sneha122 <sneha@appsmith.com> Co-authored-by: “sneha122” <“sneha@appsmith.com”> Co-authored-by: Arpit Mohan <mohanarpit@users.noreply.github.com> Co-authored-by: Nidhi Nair <nidhi@appsmith.com> Co-authored-by: Nilansh Bansal <nilansh@appsmith.com> Co-authored-by: Rishabh Rathod <rishabh.rathod@appsmith.com> Co-authored-by: vadim <vadim@appsmith.com>
|
|
@ -5,7 +5,7 @@ const LOG_LEVELS = ["debug", "error"];
|
||||||
const CONFIG_LOG_LEVEL_INDEX = 1;
|
const CONFIG_LOG_LEVEL_INDEX = 1;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
setupFiles: ["jest-canvas-mock"],
|
setupFiles: ["jest-canvas-mock", "<rootDir>/test/__mocks__/reactMarkdown.tsx"],
|
||||||
roots: ["<rootDir>/src"],
|
roots: ["<rootDir>/src"],
|
||||||
transform: {
|
transform: {
|
||||||
"^.+\\.(png|js|ts|tsx)$": "ts-jest",
|
"^.+\\.(png|js|ts|tsx)$": "ts-jest",
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,7 @@
|
||||||
"nanoid": "^2.0.4",
|
"nanoid": "^2.0.4",
|
||||||
"node-forge": "^1.3.0",
|
"node-forge": "^1.3.0",
|
||||||
"object-hash": "^3.0.0",
|
"object-hash": "^3.0.0",
|
||||||
|
"openai": "^4.64.0",
|
||||||
"path-to-regexp": "^6.3.0",
|
"path-to-regexp": "^6.3.0",
|
||||||
"popper.js": "^1.15.0",
|
"popper.js": "^1.15.0",
|
||||||
"prismjs": "^1.27.0",
|
"prismjs": "^1.27.0",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
preset: "ts-jest",
|
preset: "ts-jest",
|
||||||
roots: ["<rootDir>/src"],
|
roots: ["<rootDir>/src"],
|
||||||
|
setupFiles: ["<rootDir>../../../test/__mocks__/reactMarkdown.tsx"],
|
||||||
testEnvironment: "jsdom",
|
testEnvironment: "jsdom",
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
"\\.(css)$": "<rootDir>../../../test/__mocks__/styleMock.js",
|
"\\.(css)$": "<rootDir>../../../test/__mocks__/styleMock.js",
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,13 @@
|
||||||
"@tabler/icons-react": "^3.10.0",
|
"@tabler/icons-react": "^3.10.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"lodash": "*",
|
"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": {
|
"devDependencies": {
|
||||||
"@types/fs-extra": "^11.0.4",
|
"@types/fs-extra": "^11.0.4",
|
||||||
|
"@types/react-syntax-highlighter": "^15.5.13",
|
||||||
"eslint-plugin-storybook": "^0.6.10"
|
"eslint-plugin-storybook": "^0.6.10"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./src";
|
||||||
|
|
@ -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<HTMLDivElement>) => {
|
||||||
|
const {
|
||||||
|
// assistantName,
|
||||||
|
chatTitle,
|
||||||
|
description,
|
||||||
|
isWaitingForResponse = false,
|
||||||
|
onPromptChange,
|
||||||
|
onSubmit,
|
||||||
|
prompt,
|
||||||
|
promptInputPlaceholder,
|
||||||
|
thread,
|
||||||
|
username,
|
||||||
|
...rest
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const handleFormSubmit = useCallback(
|
||||||
|
(event: FormEvent<HTMLFormElement>) => {
|
||||||
|
event.preventDefault();
|
||||||
|
onSubmit?.();
|
||||||
|
},
|
||||||
|
[onSubmit],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handlePromptInputKeyDown = useCallback(
|
||||||
|
(event: KeyboardEvent<HTMLTextAreaElement>) => {
|
||||||
|
if (event.key === "Enter" && event.shiftKey) {
|
||||||
|
event.preventDefault();
|
||||||
|
onSubmit?.();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[onSubmit],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.root} ref={ref} {...rest}>
|
||||||
|
<div className={styles.header}>
|
||||||
|
{chatTitle != null && <ChatTitle title={chatTitle} />}
|
||||||
|
|
||||||
|
{description ?? <Text size="body">{description}</Text>}
|
||||||
|
<div className={styles.username}>
|
||||||
|
<UserAvatar username={username} />
|
||||||
|
<Text size="body">{username}</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul className={styles.thread}>
|
||||||
|
{thread.map((message: ChatMessage) => (
|
||||||
|
<ThreadMessage {...message} key={message.id} username={username} />
|
||||||
|
))}
|
||||||
|
|
||||||
|
{isWaitingForResponse && (
|
||||||
|
<li>
|
||||||
|
<Spinner />
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<form className={styles.promptForm} onSubmit={handleFormSubmit}>
|
||||||
|
<TextArea
|
||||||
|
name="prompt"
|
||||||
|
onChange={onPromptChange}
|
||||||
|
onKeyDown={handlePromptInputKeyDown}
|
||||||
|
placeholder={promptInputPlaceholder}
|
||||||
|
value={prompt}
|
||||||
|
/>
|
||||||
|
<Button isDisabled={prompt.length < MIN_PROMPT_LENGTH} type="submit">
|
||||||
|
Send
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AIChat = forwardRef(_AIChat);
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { clsx } from "clsx";
|
||||||
|
import React from "react";
|
||||||
|
import styles from "./styles.module.css";
|
||||||
|
import type { ChatTitleProps } from "./types";
|
||||||
|
|
||||||
|
export const ChatTitle = ({ className, title, ...rest }: ChatTitleProps) => {
|
||||||
|
return (
|
||||||
|
<div className={clsx(styles.root, className)} {...rest}>
|
||||||
|
<div className={styles.logo} />
|
||||||
|
{title}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./ChatTitle";
|
||||||
|
export * from "./types";
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
.root {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
/* TODO: --type-title doesn't exists. Define it */
|
||||||
|
font-size: var(--type-title, 22.499px);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
/* TODO: --type-title-lineheight doesn't exists. Define it */
|
||||||
|
line-height: var(--type-title-lineheight, 31.7px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
display: inline-block;
|
||||||
|
width: 48px;
|
||||||
|
min-width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 8px;
|
||||||
|
/* TODO: --bd-neutral doesn't exists. Define it */
|
||||||
|
border: 1px solid var(--bd-neutral, #81858b);
|
||||||
|
background: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
import type { HTMLProps } from "react";
|
||||||
|
|
||||||
|
export interface ChatTitleProps extends HTMLProps<HTMLDivElement> {
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { Text } from "@appsmith/wds";
|
||||||
|
import { clsx } from "clsx";
|
||||||
|
import React from "react";
|
||||||
|
import Markdown from "react-markdown";
|
||||||
|
import SyntaxHighlighter from "react-syntax-highlighter";
|
||||||
|
import { monokai } from "react-syntax-highlighter/dist/cjs/styles/hljs";
|
||||||
|
import { UserAvatar } from "../UserAvatar";
|
||||||
|
import styles from "./styles.module.css";
|
||||||
|
import type { ThreadMessageProps } from "./types";
|
||||||
|
|
||||||
|
export const ThreadMessage = ({
|
||||||
|
className,
|
||||||
|
content,
|
||||||
|
isAssistant,
|
||||||
|
username,
|
||||||
|
...rest
|
||||||
|
}: ThreadMessageProps) => {
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
className={clsx(styles.root, className)}
|
||||||
|
data-assistant={isAssistant}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{isAssistant ? (
|
||||||
|
<div>
|
||||||
|
<Text className={styles.content}>
|
||||||
|
<Markdown
|
||||||
|
// eslint-disable-next-line react-perf/jsx-no-new-object-as-prop
|
||||||
|
components={{
|
||||||
|
code(props) {
|
||||||
|
const { children, className, ...rest } = props;
|
||||||
|
const match = /language-(\w+)/.exec(className ?? "");
|
||||||
|
|
||||||
|
return match ? (
|
||||||
|
<SyntaxHighlighter
|
||||||
|
PreTag="div"
|
||||||
|
language={match[1]}
|
||||||
|
style={monokai}
|
||||||
|
>
|
||||||
|
{String(children).replace(/\n$/, "")}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
) : (
|
||||||
|
<code {...rest} className={className}>
|
||||||
|
{children}
|
||||||
|
</code>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{content}
|
||||||
|
</Markdown>
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<UserAvatar className={styles.userAvatar} username={username} />
|
||||||
|
<div>
|
||||||
|
<Text className={styles.content}>{content}</Text>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./ThreadMessage";
|
||||||
|
export * from "./types";
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
.root {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 12px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (min-width: 700px) {
|
||||||
|
.root {
|
||||||
|
padding: 24px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.root[data-assistant="false"] {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.root[data-assistant="false"] .sentTime {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sentTime {
|
||||||
|
margin: 0 0 8px;
|
||||||
|
/* TODO: --type-caption doesn't exists. Define it */
|
||||||
|
font-size: var(--type-caption, 12.247px);
|
||||||
|
/* TODO: --type-caption-lineheight doesn't exists. Define it */
|
||||||
|
line-height: var(--type-caption-lineheight, 17.25px);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
import type { HTMLProps } from "react";
|
||||||
|
|
||||||
|
export interface ThreadMessageProps extends HTMLProps<HTMLLIElement> {
|
||||||
|
content: string;
|
||||||
|
isAssistant: boolean;
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { clsx } from "clsx";
|
||||||
|
import React from "react";
|
||||||
|
import styles from "./styles.module.css";
|
||||||
|
import type { UserAvatarProps } from "./types";
|
||||||
|
|
||||||
|
export const UserAvatar = ({
|
||||||
|
className,
|
||||||
|
username,
|
||||||
|
...rest
|
||||||
|
}: UserAvatarProps) => {
|
||||||
|
const getNameInitials = (username: string) => {
|
||||||
|
const names = username.split(" ");
|
||||||
|
|
||||||
|
// If there is only one name, return the first character of the name.
|
||||||
|
if (names.length === 1) {
|
||||||
|
return `${names[0].charAt(0)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${names[0].charAt(0)}${names[1]?.charAt(0)}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className={clsx(styles.root, className)} {...rest}>
|
||||||
|
{getNameInitials(username)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./UserAvatar";
|
||||||
|
export * from "./types";
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
.root {
|
||||||
|
display: inline-block;
|
||||||
|
width: 28px;
|
||||||
|
min-width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
color: var(--bg-elevation-2, #fff);
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 28px;
|
||||||
|
border-radius: var(--inner-spacing-1, 4px);
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
import type { HTMLProps } from "react";
|
||||||
|
|
||||||
|
export interface UserAvatarProps extends HTMLProps<HTMLSpanElement> {
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./types";
|
||||||
|
export { AIChat } from "./AIChat";
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
.root {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: var(--border-radius-elevation-1);
|
||||||
|
border: 1px solid var(--color-bd-elevation-1);
|
||||||
|
/* TODO: --bg-elevation-1 doesn't exists. Define it */
|
||||||
|
background: var(--bg-elevation-1, #fbfcfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 22px 40px;
|
||||||
|
align-items: flex-start;
|
||||||
|
border-bottom: 1px solid var(--color-bd-elevation-1);
|
||||||
|
background: rgba(255, 255, 255, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (min-width: 700px) {
|
||||||
|
.header {
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
align-self: stretch;
|
||||||
|
padding: 0px 40px var(--inner-spacing-5) 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promptForm {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin: var(--outer-spacing-4) 0 0 0;
|
||||||
|
padding: 0 var(--inner-spacing-5) var(--inner-spacing-5)
|
||||||
|
var(--inner-spacing-5);
|
||||||
|
gap: var(--outer-spacing-3);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
export interface ChatMessage {
|
||||||
|
id: string;
|
||||||
|
content: string;
|
||||||
|
isAssistant: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AIChatProps {
|
||||||
|
thread: ChatMessage[];
|
||||||
|
prompt: string;
|
||||||
|
username: string;
|
||||||
|
promptInputPlaceholder?: string;
|
||||||
|
chatTitle?: string;
|
||||||
|
description?: string;
|
||||||
|
assistantName?: string;
|
||||||
|
isWaitingForResponse?: boolean;
|
||||||
|
onPromptChange: (prompt: string) => void;
|
||||||
|
onSubmit?: () => void;
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
export * from "./components/AIChat";
|
||||||
export * from "./components/Icon";
|
export * from "./components/Icon";
|
||||||
export * from "./components/Button";
|
export * from "./components/Button";
|
||||||
export * from "./components/IconButton";
|
export * from "./components/IconButton";
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
import React from "react";
|
||||||
|
export const AIChatIcon = () => <svg xmlns="http://www.w3.org/2000/svg" width="16" height="17" fill="none"><path fill="#000" fill-opacity=".25" fill-rule="evenodd" d="M1.5 1A1.5 1.5 0 0 0 0 2.5v8A1.5 1.5 0 0 0 1.5 12H2V4.5A1.5 1.5 0 0 1 3.5 3H13v-.5A1.5 1.5 0 0 0 11.5 1z" clip-rule="evenodd"/><mask id="a" fill="#fff"><path fill-rule="evenodd" d="M3.5 3A1.5 1.5 0 0 0 2 4.5v8A1.5 1.5 0 0 0 3.5 14H10l2.146 2.146a.5.5 0 0 0 .854-.353V14h.5a1.5 1.5 0 0 0 1.5-1.5v-8A1.5 1.5 0 0 0 13.5 3z" clip-rule="evenodd"/></mask><path fill="#000" d="m10 14 .707-.707-.293-.293H10zm3 0v-1h-1v1zM3 4.5a.5.5 0 0 1 .5-.5V2A2.5 2.5 0 0 0 1 4.5zm0 8v-8H1v8zm.5.5a.5.5 0 0 1-.5-.5H1A2.5 2.5 0 0 0 3.5 15zm6.5 0H3.5v2H10zm2.854 2.44-2.147-2.147-1.414 1.414 2.146 2.147zm-.854.353a.5.5 0 0 1 .854-.354l-1.415 1.415c.945.945 2.561.275 2.561-1.061zM12 14v1.793h2V14zm1.5-1H13v2h.5zm.5-.5a.5.5 0 0 1-.5.5v2a2.5 2.5 0 0 0 2.5-2.5zm0-8v8h2v-8zm-.5-.5a.5.5 0 0 1 .5.5h2A2.5 2.5 0 0 0 13.5 2zm-10 0h10V2h-10z" mask="url(#a)"/><path stroke="#000" stroke-opacity=".75" d="m8.536 6.27.6 1.402.08.184.183.078 1.403.602-1.403.6-.184.08-.078.183-.601 1.403-.602-1.403-.078-.184-.184-.078-1.403-.601 1.403-.602.184-.078.078-.184z"/></svg>;
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
export const ComboboxSelectIcon = () => <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none"><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M14.5 2.5h-12a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h7M14.5 7.5l-1 1-1-1"/><circle cx="5.5" cy="7.5" r="2" stroke="#000"/><path fill="#000" d="M7.354 8.646 7 8.293 6.293 9l.353.354zm.292 1.708a.5.5 0 0 0 .708-.708zm-1-1 1 1 .708-.708-1-1z"/></svg>;
|
export const ComboboxSelectIcon = () => <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none"><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M14.5 2.5h-12a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h7M14.5 7.5l-1 1-1-1"/><circle cx="5.5" cy="7.5" r="2.079" stroke="#000"/><path fill="#000" d="m7.534 8.685-.424-.424-.849.849.424.424zm.042 1.74a.6.6 0 0 0 .848-.85zm-.89-.891.89.89.848-.848-.89-.89z"/></svg>;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
import React from "react";
|
||||||
|
export const DatePickerIcon = () => <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none"><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M12.5 1.5h-10a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1v-10a1 1 0 0 0-1-1M9.5 5.5v8M5.5 5.5v8M1.5 5.5h12M1.5 9.5h12M4.5 3.5v-3m6 3v-3"/></svg>;
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
export const InputIcon = () => <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none"><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="m7.5 9.5-.5-1m-3.5 1 .5-1m0 0 1.5-3 1.5 3m-3 0h3"/><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M14.5 2.5h-12a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h7M14.5 7.5l-1 1-1-1"/></svg>;
|
export const InputIcon = () => <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none"><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="m7.5 9.5-.5-1m-3.5 1 .5-1m0 0 1.5-3 1.5 3m-3 0h3"/><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".25" d="M12.5 6.5h1m1 0h-1m0 0v8m-1 0h2"/><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M14.5 2.5h-12a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h7"/></svg>;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
import React from "react";
|
||||||
|
export const AIChatThumbnail = () => <svg xmlns="http://www.w3.org/2000/svg" width="72" height="76" fill="none"><mask id="a" fill="#fff"><path fill-rule="evenodd" d="M40 21a3 3 0 0 1 3 3v18a3 3 0 0 1-3 3H21l-7.257 8.063c-.613.681-1.743.247-1.743-.669V45H9a3 3 0 0 1-3-3V24a3 3 0 0 1 3-3z" clip-rule="evenodd"/></mask><path fill="#fff" fill-rule="evenodd" d="M40 21a3 3 0 0 1 3 3v18a3 3 0 0 1-3 3H21l-7.257 8.063c-.613.681-1.743.247-1.743-.669V45H9a3 3 0 0 1-3-3V24a3 3 0 0 1 3-3z" clip-rule="evenodd"/><path fill="#CDD5DF" d="m21 45-.743-.669.298-.331H21zm-7.257 8.063.744.669zM12 45v-1h1v1zm30-21a2 2 0 0 0-2-2v-2a4 4 0 0 1 4 4zm0 18V24h2v18zm-2 2a2 2 0 0 0 2-2h2a4 4 0 0 1-4 4zm-19 0h19v2H21zm-8 8.394 7.257-8.063 1.486 1.338-7.256 8.063zm0 0 1.487 1.338C13.26 55.094 11 54.227 11 52.394zM13 45v7.394h-2V45zm-4-1h3v2H9zm-2-2a2 2 0 0 0 2 2v2a4 4 0 0 1-4-4zm0-18v18H5V24zm2-2a2 2 0 0 0-2 2H5a4 4 0 0 1 4-4zm31 0H9v-2h31z" mask="url(#a)"/><mask id="b" fill="#fff"><path fill-rule="evenodd" d="M32 29a3 3 0 0 0-3 3v18a3 3 0 0 0 3 3h19l7.257 8.063c.613.681 1.743.247 1.743-.669V53h3a3 3 0 0 0 3-3V32a3 3 0 0 0-3-3z" clip-rule="evenodd"/></mask><path fill="#FFBFA1" fill-rule="evenodd" d="M32 29a3 3 0 0 0-3 3v18a3 3 0 0 0 3 3h19l7.257 8.063c.613.681 1.743.247 1.743-.669V53h3a3 3 0 0 0 3-3V32a3 3 0 0 0-3-3z" clip-rule="evenodd"/><path fill="#CC3D00" d="m51 53 .743-.669-.298-.331H51zm7.257 8.063-.744.669zM60 53v-1h-1v1zM30 32a2 2 0 0 1 2-2v-2a4 4 0 0 0-4 4zm0 18V32h-2v18zm2 2a2 2 0 0 1-2-2h-2a4 4 0 0 0 4 4zm19 0H32v2h19zm8 8.394-7.257-8.063-1.486 1.338 7.256 8.063zm0 0-1.487 1.338C58.74 63.094 61 62.227 61 60.394zM59 53v7.394h2V53zm4-1h-3v2h3zm2-2a2 2 0 0 1-2 2v2a4 4 0 0 0 4-4zm0-18v18h2V32zm-2-2a2 2 0 0 1 2 2h2a4 4 0 0 0-4-4zm-31 0h31v-2H32z" mask="url(#b)"/><path fill="#fff" stroke="#CC3D00" d="M41.434 42.657a8.5 8.5 0 0 0 4.223-4.223 8.5 8.5 0 0 0 4.223 4.223 8.5 8.5 0 0 0-4.223 4.223 8.5 8.5 0 0 0-4.223-4.223ZM51.17 34.263l.073-.145.072.145a6.5 6.5 0 0 0 2.907 2.907l.145.073-.145.072a6.5 6.5 0 0 0-2.907 2.907l-.072.145-.073-.145a6.5 6.5 0 0 0-2.907-2.907l-.145-.072.145-.073a6.5 6.5 0 0 0 2.907-2.907Z"/></svg>;
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
import React from "react";
|
||||||
|
export const DatePickerThumbnail = () => <svg xmlns="http://www.w3.org/2000/svg" width="72" height="76" fill="none"><rect width="55" height="23" x="8.5" y="26.5" fill="#fff" rx="2.5"/><rect width="55" height="23" x="8.5" y="26.5" stroke="#CDD5DF" rx="2.5"/><path stroke="#CC3D00" stroke-linecap="round" stroke-linejoin="round" d="M25.5 32.5h-10a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1v-10a1 1 0 0 0-1-1M22.5 36.5v8M18.5 36.5v8M14.5 36.5h12M14.5 40.5h12M17.5 34.5v-3m6 3v-3"/><path stroke="#99A4B3" stroke-linecap="round" stroke-linejoin="round" d="m56.5 36.5-3 3-3-3"/></svg>;
|
||||||
1
app/client/packages/icons/src/icons/Icons/AIChat.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="17" fill="none"><path fill="#000" fill-opacity=".25" fill-rule="evenodd" d="M1.5 1A1.5 1.5 0 0 0 0 2.5v8A1.5 1.5 0 0 0 1.5 12H2V4.5A1.5 1.5 0 0 1 3.5 3H13v-.5A1.5 1.5 0 0 0 11.5 1z" clip-rule="evenodd"/><mask id="a" fill="#fff"><path fill-rule="evenodd" d="M3.5 3A1.5 1.5 0 0 0 2 4.5v8A1.5 1.5 0 0 0 3.5 14H10l2.146 2.146a.5.5 0 0 0 .854-.353V14h.5a1.5 1.5 0 0 0 1.5-1.5v-8A1.5 1.5 0 0 0 13.5 3z" clip-rule="evenodd"/></mask><path fill="#000" d="m10 14 .707-.707-.293-.293H10zm3 0v-1h-1v1zM3 4.5a.5.5 0 0 1 .5-.5V2A2.5 2.5 0 0 0 1 4.5zm0 8v-8H1v8zm.5.5a.5.5 0 0 1-.5-.5H1A2.5 2.5 0 0 0 3.5 15zm6.5 0H3.5v2H10zm2.854 2.44-2.147-2.147-1.414 1.414 2.146 2.147zm-.854.353a.5.5 0 0 1 .854-.354l-1.415 1.415c.945.945 2.561.275 2.561-1.061zM12 14v1.793h2V14zm1.5-1H13v2h.5zm.5-.5a.5.5 0 0 1-.5.5v2a2.5 2.5 0 0 0 2.5-2.5zm0-8v8h2v-8zm-.5-.5a.5.5 0 0 1 .5.5h2A2.5 2.5 0 0 0 13.5 2zm-10 0h10V2h-10z" mask="url(#a)"/><path stroke="#000" stroke-opacity=".75" d="m8.536 6.27.6 1.402.08.184.183.078 1.403.602-1.403.6-.184.08-.078.183-.601 1.403-.602-1.403-.078-.184-.184-.078-1.403-.601 1.403-.602.184-.078.078-.184z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -1 +1 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none"><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M14.5 2.5h-12a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h7M14.5 7.5l-1 1-1-1"/><circle cx="5.5" cy="7.5" r="2" stroke="#000"/><path fill="#000" d="M7.354 8.646 7 8.293 6.293 9l.353.354zm.292 1.708a.5.5 0 0 0 .708-.708zm-1-1 1 1 .708-.708-1-1z"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none"><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M14.5 2.5h-12a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h7M14.5 7.5l-1 1-1-1"/><circle cx="5.5" cy="7.5" r="2.079" stroke="#000"/><path fill="#000" d="m7.534 8.685-.424-.424-.849.849.424.424zm.042 1.74a.6.6 0 0 0 .848-.85zm-.89-.891.89.89.848-.848-.89-.89z"/></svg>
|
||||||
|
Before Width: | Height: | Size: 383 B After Width: | Height: | Size: 397 B |
1
app/client/packages/icons/src/icons/Icons/DatePicker.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none"><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M12.5 1.5h-10a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1v-10a1 1 0 0 0-1-1M9.5 5.5v8M5.5 5.5v8M1.5 5.5h12M1.5 9.5h12M4.5 3.5v-3m6 3v-3"/></svg>
|
||||||
|
After Width: | Height: | Size: 293 B |
|
|
@ -1 +1 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none"><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="m7.5 9.5-.5-1m-3.5 1 .5-1m0 0 1.5-3 1.5 3m-3 0h3"/><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M14.5 2.5h-12a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h7M14.5 7.5l-1 1-1-1"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none"><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="m7.5 9.5-.5-1m-3.5 1 .5-1m0 0 1.5-3 1.5 3m-3 0h3"/><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".25" d="M12.5 6.5h1m1 0h-1m0 0v8m-1 0h2"/><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" d="M14.5 2.5h-12a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h7"/></svg>
|
||||||
|
Before Width: | Height: | Size: 338 B After Width: | Height: | Size: 445 B |
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="72" height="76" fill="none"><mask id="a" fill="#fff"><path fill-rule="evenodd" d="M40 21a3 3 0 0 1 3 3v18a3 3 0 0 1-3 3H21l-7.257 8.063c-.613.681-1.743.247-1.743-.669V45H9a3 3 0 0 1-3-3V24a3 3 0 0 1 3-3z" clip-rule="evenodd"/></mask><path fill="#fff" fill-rule="evenodd" d="M40 21a3 3 0 0 1 3 3v18a3 3 0 0 1-3 3H21l-7.257 8.063c-.613.681-1.743.247-1.743-.669V45H9a3 3 0 0 1-3-3V24a3 3 0 0 1 3-3z" clip-rule="evenodd"/><path fill="#CDD5DF" d="m21 45-.743-.669.298-.331H21zm-7.257 8.063.744.669zM12 45v-1h1v1zm30-21a2 2 0 0 0-2-2v-2a4 4 0 0 1 4 4zm0 18V24h2v18zm-2 2a2 2 0 0 0 2-2h2a4 4 0 0 1-4 4zm-19 0h19v2H21zm-8 8.394 7.257-8.063 1.486 1.338-7.256 8.063zm0 0 1.487 1.338C13.26 55.094 11 54.227 11 52.394zM13 45v7.394h-2V45zm-4-1h3v2H9zm-2-2a2 2 0 0 0 2 2v2a4 4 0 0 1-4-4zm0-18v18H5V24zm2-2a2 2 0 0 0-2 2H5a4 4 0 0 1 4-4zm31 0H9v-2h31z" mask="url(#a)"/><mask id="b" fill="#fff"><path fill-rule="evenodd" d="M32 29a3 3 0 0 0-3 3v18a3 3 0 0 0 3 3h19l7.257 8.063c.613.681 1.743.247 1.743-.669V53h3a3 3 0 0 0 3-3V32a3 3 0 0 0-3-3z" clip-rule="evenodd"/></mask><path fill="#FFBFA1" fill-rule="evenodd" d="M32 29a3 3 0 0 0-3 3v18a3 3 0 0 0 3 3h19l7.257 8.063c.613.681 1.743.247 1.743-.669V53h3a3 3 0 0 0 3-3V32a3 3 0 0 0-3-3z" clip-rule="evenodd"/><path fill="#CC3D00" d="m51 53 .743-.669-.298-.331H51zm7.257 8.063-.744.669zM60 53v-1h-1v1zM30 32a2 2 0 0 1 2-2v-2a4 4 0 0 0-4 4zm0 18V32h-2v18zm2 2a2 2 0 0 1-2-2h-2a4 4 0 0 0 4 4zm19 0H32v2h19zm8 8.394-7.257-8.063-1.486 1.338 7.256 8.063zm0 0-1.487 1.338C58.74 63.094 61 62.227 61 60.394zM59 53v7.394h2V53zm4-1h-3v2h3zm2-2a2 2 0 0 1-2 2v2a4 4 0 0 0 4-4zm0-18v18h2V32zm-2-2a2 2 0 0 1 2 2h2a4 4 0 0 0-4-4zm-31 0h31v-2H32z" mask="url(#b)"/><path fill="#fff" stroke="#CC3D00" d="M41.434 42.657a8.5 8.5 0 0 0 4.223-4.223 8.5 8.5 0 0 0 4.223 4.223 8.5 8.5 0 0 0-4.223 4.223 8.5 8.5 0 0 0-4.223-4.223ZM51.17 34.263l.073-.145.072.145a6.5 6.5 0 0 0 2.907 2.907l.145.073-.145.072a6.5 6.5 0 0 0-2.907 2.907l-.072.145-.073-.145a6.5 6.5 0 0 0-2.907-2.907l-.145-.072.145-.073a6.5 6.5 0 0 0 2.907-2.907Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 2.0 KiB |
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="72" height="76" fill="none"><rect width="55" height="23" x="8.5" y="26.5" fill="#fff" rx="2.5"/><rect width="55" height="23" x="8.5" y="26.5" stroke="#CDD5DF" rx="2.5"/><path stroke="#CC3D00" stroke-linecap="round" stroke-linejoin="round" d="M25.5 32.5h-10a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1v-10a1 1 0 0 0-1-1M22.5 36.5v8M18.5 36.5v8M14.5 36.5h12M14.5 40.5h12M17.5 34.5v-3m6 3v-3"/><path stroke="#99A4B3" stroke-linecap="round" stroke-linejoin="round" d="m56.5 36.5-3 3-3-3"/></svg>
|
||||||
|
After Width: | Height: | Size: 542 B |
|
|
@ -1,8 +1,10 @@
|
||||||
|
export { AIChatThumbnail } from "./components/Thumbnails/AIChatThumbnail";
|
||||||
export { ButtonThumbnail } from "./components/Thumbnails/ButtonThumbnail";
|
export { ButtonThumbnail } from "./components/Thumbnails/ButtonThumbnail";
|
||||||
export { CheckboxGroupThumbnail } from "./components/Thumbnails/CheckboxGroupThumbnail";
|
export { CheckboxGroupThumbnail } from "./components/Thumbnails/CheckboxGroupThumbnail";
|
||||||
export { CheckboxThumbnail } from "./components/Thumbnails/CheckboxThumbnail";
|
export { CheckboxThumbnail } from "./components/Thumbnails/CheckboxThumbnail";
|
||||||
export { ComboboxSelectThumbnail } from "./components/Thumbnails/ComboboxSelectThumbnail";
|
export { ComboboxSelectThumbnail } from "./components/Thumbnails/ComboboxSelectThumbnail";
|
||||||
export { CurrencyInputThumbnail } from "./components/Thumbnails/CurrencyInputThumbnail";
|
export { CurrencyInputThumbnail } from "./components/Thumbnails/CurrencyInputThumbnail";
|
||||||
|
export { DatePickerThumbnail } from "./components/Thumbnails/DatePickerThumbnail";
|
||||||
export { EmailInputThumbnail } from "./components/Thumbnails/EmailInputThumbnail";
|
export { EmailInputThumbnail } from "./components/Thumbnails/EmailInputThumbnail";
|
||||||
export { HeadingThumbnail } from "./components/Thumbnails/HeadingThumbnail";
|
export { HeadingThumbnail } from "./components/Thumbnails/HeadingThumbnail";
|
||||||
export { IconButtonThumbnail } from "./components/Thumbnails/IconButtonThumbnail";
|
export { IconButtonThumbnail } from "./components/Thumbnails/IconButtonThumbnail";
|
||||||
|
|
@ -25,11 +27,13 @@ export { SwitchThumbnail } from "./components/Thumbnails/SwitchThumbnail";
|
||||||
export { TableThumbnail } from "./components/Thumbnails/TableThumbnail";
|
export { TableThumbnail } from "./components/Thumbnails/TableThumbnail";
|
||||||
export { ToolbarButtonsThumbnail } from "./components/Thumbnails/ToolbarButtonsThumbnail";
|
export { ToolbarButtonsThumbnail } from "./components/Thumbnails/ToolbarButtonsThumbnail";
|
||||||
export { ZoneThumbnail } from "./components/Thumbnails/ZoneThumbnail";
|
export { ZoneThumbnail } from "./components/Thumbnails/ZoneThumbnail";
|
||||||
|
export { AIChatIcon } from "./components/Icons/AIChatIcon";
|
||||||
export { ButtonIcon } from "./components/Icons/ButtonIcon";
|
export { ButtonIcon } from "./components/Icons/ButtonIcon";
|
||||||
export { CheckboxGroupIcon } from "./components/Icons/CheckboxGroupIcon";
|
export { CheckboxGroupIcon } from "./components/Icons/CheckboxGroupIcon";
|
||||||
export { CheckboxIcon } from "./components/Icons/CheckboxIcon";
|
export { CheckboxIcon } from "./components/Icons/CheckboxIcon";
|
||||||
export { ComboboxSelectIcon } from "./components/Icons/ComboboxSelectIcon";
|
export { ComboboxSelectIcon } from "./components/Icons/ComboboxSelectIcon";
|
||||||
export { CurrencyInputIcon } from "./components/Icons/CurrencyInputIcon";
|
export { CurrencyInputIcon } from "./components/Icons/CurrencyInputIcon";
|
||||||
|
export { DatePickerIcon } from "./components/Icons/DatePickerIcon";
|
||||||
export { EmailInputIcon } from "./components/Icons/EmailInputIcon";
|
export { EmailInputIcon } from "./components/Icons/EmailInputIcon";
|
||||||
export { HeadingIcon } from "./components/Icons/HeadingIcon";
|
export { HeadingIcon } from "./components/Icons/HeadingIcon";
|
||||||
export { IconButtonIcon } from "./components/Icons/IconButtonIcon";
|
export { IconButtonIcon } from "./components/Icons/IconButtonIcon";
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
import { Meta } from "@storybook/addon-docs";
|
import { Meta } from "@storybook/addon-docs";
|
||||||
import { Flex } from "@appsmith/wds";
|
import { Flex } from "@appsmith/wds";
|
||||||
|
import { AIChatIcon } from "../components/Icons/AIChatIcon";
|
||||||
import { ButtonIcon } from "../components/Icons/ButtonIcon";
|
import { ButtonIcon } from "../components/Icons/ButtonIcon";
|
||||||
import { CheckboxGroupIcon } from "../components/Icons/CheckboxGroupIcon";
|
import { CheckboxGroupIcon } from "../components/Icons/CheckboxGroupIcon";
|
||||||
import { CheckboxIcon } from "../components/Icons/CheckboxIcon";
|
import { CheckboxIcon } from "../components/Icons/CheckboxIcon";
|
||||||
import { ComboboxSelectIcon } from "../components/Icons/ComboboxSelectIcon";
|
import { ComboboxSelectIcon } from "../components/Icons/ComboboxSelectIcon";
|
||||||
import { CurrencyInputIcon } from "../components/Icons/CurrencyInputIcon";
|
import { CurrencyInputIcon } from "../components/Icons/CurrencyInputIcon";
|
||||||
|
import { DatePickerIcon } from "../components/Icons/DatePickerIcon";
|
||||||
import { EmailInputIcon } from "../components/Icons/EmailInputIcon";
|
import { EmailInputIcon } from "../components/Icons/EmailInputIcon";
|
||||||
import { HeadingIcon } from "../components/Icons/HeadingIcon";
|
import { HeadingIcon } from "../components/Icons/HeadingIcon";
|
||||||
import { IconButtonIcon } from "../components/Icons/IconButtonIcon";
|
import { IconButtonIcon } from "../components/Icons/IconButtonIcon";
|
||||||
|
|
@ -36,11 +38,13 @@ Icon set for Entity Explorer Panel, which provides a visual representation of th
|
||||||
export const Icons = () => {
|
export const Icons = () => {
|
||||||
return (
|
return (
|
||||||
<Flex gap="spacing-4" wrap="wrap">
|
<Flex gap="spacing-4" wrap="wrap">
|
||||||
|
<AIChatIcon />
|
||||||
<ButtonIcon />
|
<ButtonIcon />
|
||||||
<CheckboxGroupIcon />
|
<CheckboxGroupIcon />
|
||||||
<CheckboxIcon />
|
<CheckboxIcon />
|
||||||
<ComboboxSelectIcon />
|
<ComboboxSelectIcon />
|
||||||
<CurrencyInputIcon />
|
<CurrencyInputIcon />
|
||||||
|
<DatePickerIcon />
|
||||||
<EmailInputIcon />
|
<EmailInputIcon />
|
||||||
<HeadingIcon />
|
<HeadingIcon />
|
||||||
<IconButtonIcon />
|
<IconButtonIcon />
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
import { Meta } from "@storybook/addon-docs";
|
import { Meta } from "@storybook/addon-docs";
|
||||||
import { Flex } from "@appsmith/wds";
|
import { Flex } from "@appsmith/wds";
|
||||||
|
import { AIChatThumbnail } from "../components/Thumbnails/AIChatThumbnail";
|
||||||
import { ButtonThumbnail } from "../components/Thumbnails/ButtonThumbnail";
|
import { ButtonThumbnail } from "../components/Thumbnails/ButtonThumbnail";
|
||||||
import { CheckboxGroupThumbnail } from "../components/Thumbnails/CheckboxGroupThumbnail";
|
import { CheckboxGroupThumbnail } from "../components/Thumbnails/CheckboxGroupThumbnail";
|
||||||
import { CheckboxThumbnail } from "../components/Thumbnails/CheckboxThumbnail";
|
import { CheckboxThumbnail } from "../components/Thumbnails/CheckboxThumbnail";
|
||||||
import { ComboboxSelectThumbnail } from "../components/Thumbnails/ComboboxSelectThumbnail";
|
import { ComboboxSelectThumbnail } from "../components/Thumbnails/ComboboxSelectThumbnail";
|
||||||
import { CurrencyInputThumbnail } from "../components/Thumbnails/CurrencyInputThumbnail";
|
import { CurrencyInputThumbnail } from "../components/Thumbnails/CurrencyInputThumbnail";
|
||||||
|
import { DatePickerThumbnail } from "../components/Thumbnails/DatePickerThumbnail";
|
||||||
import { EmailInputThumbnail } from "../components/Thumbnails/EmailInputThumbnail";
|
import { EmailInputThumbnail } from "../components/Thumbnails/EmailInputThumbnail";
|
||||||
import { HeadingThumbnail } from "../components/Thumbnails/HeadingThumbnail";
|
import { HeadingThumbnail } from "../components/Thumbnails/HeadingThumbnail";
|
||||||
import { IconButtonThumbnail } from "../components/Thumbnails/IconButtonThumbnail";
|
import { IconButtonThumbnail } from "../components/Thumbnails/IconButtonThumbnail";
|
||||||
|
|
@ -37,11 +39,13 @@ Icon set for Widget Explorer Panel, which provides a visual representation of th
|
||||||
export const Icons = () => {
|
export const Icons = () => {
|
||||||
return (
|
return (
|
||||||
<Flex gap="spacing-4" wrap="wrap">
|
<Flex gap="spacing-4" wrap="wrap">
|
||||||
|
<AIChatThumbnail />
|
||||||
<ButtonThumbnail />
|
<ButtonThumbnail />
|
||||||
<CheckboxGroupThumbnail />
|
<CheckboxGroupThumbnail />
|
||||||
<CheckboxThumbnail />
|
<CheckboxThumbnail />
|
||||||
<ComboboxSelectThumbnail />
|
<ComboboxSelectThumbnail />
|
||||||
<CurrencyInputThumbnail />
|
<CurrencyInputThumbnail />
|
||||||
|
<DatePickerThumbnail />
|
||||||
<EmailInputThumbnail />
|
<EmailInputThumbnail />
|
||||||
<HeadingThumbnail />
|
<HeadingThumbnail />
|
||||||
<IconButtonThumbnail />
|
<IconButtonThumbnail />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
import WDSAIChatWidget from "./widget";
|
||||||
|
|
||||||
|
export { WDSAIChatWidget };
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import type { AnvilConfig } from "WidgetProvider/constants";
|
||||||
|
|
||||||
|
export const anvilConfig: AnvilConfig = {
|
||||||
|
isLargeWidget: false,
|
||||||
|
widgetSize: {
|
||||||
|
minWidth: {
|
||||||
|
base: "100%",
|
||||||
|
"180px": "sizing-30",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
|
||||||
|
|
||||||
|
export const autocompleteConfig = {
|
||||||
|
isVisible: DefaultAutocompleteDefinitions.isVisible,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { ResponsiveBehavior } from "layoutSystems/common/utils/constants";
|
||||||
|
import type { WidgetDefaultProps } from "WidgetProvider/constants";
|
||||||
|
|
||||||
|
export const defaultsConfig = {
|
||||||
|
isVisible: true,
|
||||||
|
widgetName: "AIChat",
|
||||||
|
widgetType: "AI_CHAT",
|
||||||
|
version: 1,
|
||||||
|
responsiveBehavior: ResponsiveBehavior.Fill,
|
||||||
|
} as unknown as WidgetDefaultProps;
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { anvilConfig } from "./anvilConfig";
|
||||||
|
import { metaConfig } from "./metaConfig";
|
||||||
|
import { defaultsConfig } from "./defaultConfig";
|
||||||
|
import { propertyPaneContent } from "./propertyPaneContent";
|
||||||
|
import { propertyPaneStyle } from "./propertyPaneStyle";
|
||||||
|
import { methodsConfig } from "./methodsConfig";
|
||||||
|
import { autocompleteConfig } from "./autocompleteConfig";
|
||||||
|
|
||||||
|
export {
|
||||||
|
anvilConfig,
|
||||||
|
metaConfig,
|
||||||
|
defaultsConfig,
|
||||||
|
propertyPaneContent,
|
||||||
|
propertyPaneStyle,
|
||||||
|
methodsConfig,
|
||||||
|
autocompleteConfig,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { WIDGET_TAGS } from "constants/WidgetConstants";
|
||||||
|
import type { WidgetBaseConfiguration } from "WidgetProvider/constants";
|
||||||
|
|
||||||
|
export const metaConfig: WidgetBaseConfiguration = {
|
||||||
|
name: "AIChat",
|
||||||
|
tags: [WIDGET_TAGS.CONTENT],
|
||||||
|
needsMeta: true,
|
||||||
|
searchTags: ["chat"],
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { AIChatIcon, AIChatThumbnail } from "appsmith-icons";
|
||||||
|
|
||||||
|
export const methodsConfig = {
|
||||||
|
IconCmp: AIChatIcon,
|
||||||
|
ThumbnailCmp: AIChatThumbnail,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
import { ValidationTypes } from "constants/WidgetValidation";
|
||||||
|
|
||||||
|
export const propertyPaneContent = [
|
||||||
|
{
|
||||||
|
sectionName: "General",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
helpText: "Select a query to submit when a chat message is sent.",
|
||||||
|
propertyName: "query",
|
||||||
|
label: "Query to trigger",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
placeholderText: "Value",
|
||||||
|
isJSConvertible: false,
|
||||||
|
isBindProperty: false,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
dependencies: ["queryData", "queryRun"],
|
||||||
|
updateHook: (
|
||||||
|
_props: unknown,
|
||||||
|
propertyPath: string,
|
||||||
|
propertyValue: string,
|
||||||
|
) => {
|
||||||
|
const propertiesToUpdate = [{ propertyPath, propertyValue }];
|
||||||
|
|
||||||
|
propertiesToUpdate.push({
|
||||||
|
propertyPath: "queryData",
|
||||||
|
propertyValue: `{{${propertyValue}.data}}`,
|
||||||
|
});
|
||||||
|
propertiesToUpdate.push({
|
||||||
|
propertyPath: "queryRun",
|
||||||
|
propertyValue: propertyValue,
|
||||||
|
});
|
||||||
|
|
||||||
|
return propertiesToUpdate;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
helpText: "Adds a header to the chat",
|
||||||
|
propertyName: "chatTitle",
|
||||||
|
label: "Title",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
isJSConvertible: false,
|
||||||
|
isBindProperty: false,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.TEXT },
|
||||||
|
defaultValue: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
helpText:
|
||||||
|
"Adds a description to help users understand how to use the chat",
|
||||||
|
propertyName: "chatDescription",
|
||||||
|
label: "Description",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
isJSConvertible: false,
|
||||||
|
isBindProperty: false,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.TEXT },
|
||||||
|
defaultValue: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
helpText: "Adds a placeholder text to the message input box",
|
||||||
|
propertyName: "promptInputPlaceholder",
|
||||||
|
label: "Placeholder",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
isJSConvertible: false,
|
||||||
|
isBindProperty: false,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.TEXT },
|
||||||
|
defaultValue: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
helpText: "Gives the open AI Assistant a name to be displayed in chat",
|
||||||
|
propertyName: "assistantName",
|
||||||
|
label: "Assistant Name",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
isJSConvertible: false,
|
||||||
|
isBindProperty: false,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.TEXT },
|
||||||
|
defaultValue: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
helpText: "Configures a prompt for the assistant",
|
||||||
|
propertyName: "systemPrompt",
|
||||||
|
label: "Prompt",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
isJSConvertible: false,
|
||||||
|
isBindProperty: false,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.TEXT },
|
||||||
|
defaultValue: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
helpText: "Controls the visibility of the widget",
|
||||||
|
propertyName: "isVisible",
|
||||||
|
label: "Visible",
|
||||||
|
controlType: "SWITCH",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.BOOLEAN },
|
||||||
|
defaultValue: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sectionName: "Hidden props",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
propertyName: "queryData",
|
||||||
|
label: "",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
hidden: () => true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propertyName: "queryRun",
|
||||||
|
label: "",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
hidden: () => true,
|
||||||
|
},
|
||||||
|
// Fake hidden prop to pass the username to the widget
|
||||||
|
{
|
||||||
|
propertyName: "username",
|
||||||
|
label: "",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
defaultValue: "{{appsmith.user.username}}",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
hidden: () => true,
|
||||||
|
invisible: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export const propertyPaneStyle = [];
|
||||||
|
|
@ -0,0 +1,214 @@
|
||||||
|
import { AIChat, type ChatMessage } from "@appsmith/wds";
|
||||||
|
import {
|
||||||
|
EventType,
|
||||||
|
type ExecutionResult,
|
||||||
|
} from "constants/AppsmithActionConstants/ActionConstants";
|
||||||
|
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
|
||||||
|
import React, { type FormEvent, type ReactNode } from "react";
|
||||||
|
import type {
|
||||||
|
AnvilConfig,
|
||||||
|
AutocompletionDefinitions,
|
||||||
|
WidgetBaseConfiguration,
|
||||||
|
WidgetDefaultProps,
|
||||||
|
} from "WidgetProvider/constants";
|
||||||
|
import type { DerivedPropertiesMap } from "WidgetProvider/factory";
|
||||||
|
import type { WidgetProps, WidgetState } from "widgets/BaseWidget";
|
||||||
|
import BaseWidget from "widgets/BaseWidget";
|
||||||
|
import type { ContainerWidgetProps } from "widgets/ContainerWidget/widget";
|
||||||
|
import {
|
||||||
|
anvilConfig,
|
||||||
|
autocompleteConfig,
|
||||||
|
defaultsConfig,
|
||||||
|
metaConfig,
|
||||||
|
methodsConfig,
|
||||||
|
propertyPaneContent,
|
||||||
|
propertyPaneStyle,
|
||||||
|
} from "./config";
|
||||||
|
|
||||||
|
export interface WDSAIChatWidgetProps
|
||||||
|
extends ContainerWidgetProps<WidgetProps> {}
|
||||||
|
export interface Message {
|
||||||
|
id: string;
|
||||||
|
content: string;
|
||||||
|
role: "assistant" | "user" | "system";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State extends WidgetState {
|
||||||
|
messages: Message[];
|
||||||
|
prompt: string;
|
||||||
|
isWaitingForResponse: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
class WDSAIChatWidget extends BaseWidget<WDSAIChatWidgetProps, State> {
|
||||||
|
static type = "WDS_AI_CHAT_WIDGET";
|
||||||
|
|
||||||
|
state = {
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
id: "1",
|
||||||
|
content: "Hello! How can I help you?",
|
||||||
|
role: "assistant" as const,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "2",
|
||||||
|
content: "Find stuck support requests",
|
||||||
|
role: "user" as const,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "3",
|
||||||
|
content:
|
||||||
|
"I'm finding these customer support requests that have been waiting for a response for over a day:",
|
||||||
|
role: "assistant" as const,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
prompt: "",
|
||||||
|
isWaitingForResponse: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static getConfig(): WidgetBaseConfiguration {
|
||||||
|
return metaConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDefaults(): WidgetDefaultProps {
|
||||||
|
return defaultsConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getPropertyPaneConfig() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
static getPropertyPaneContentConfig() {
|
||||||
|
return propertyPaneContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getPropertyPaneStyleConfig() {
|
||||||
|
return propertyPaneStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getMethods() {
|
||||||
|
return methodsConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getAutocompleteDefinitions(): AutocompletionDefinitions {
|
||||||
|
return autocompleteConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getSetterConfig(): SetterConfig | null {
|
||||||
|
return {
|
||||||
|
__setters: {
|
||||||
|
setVisibility: {
|
||||||
|
path: "isVisible",
|
||||||
|
type: "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDerivedPropertiesMap(): DerivedPropertiesMap {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDefaultPropertiesMap(): Record<string, string> {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getMetaPropertiesMap(): Record<string, unknown> {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getAnvilConfig(): AnvilConfig | null {
|
||||||
|
return anvilConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getStylesheetConfig(): Stylesheet {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
adaptMessages(messages: Message[]): ChatMessage[] {
|
||||||
|
return messages.map((message) => ({
|
||||||
|
...message,
|
||||||
|
isAssistant: message.role === "assistant",
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMessageSubmit = (event?: FormEvent<HTMLFormElement>) => {
|
||||||
|
event?.preventDefault();
|
||||||
|
|
||||||
|
this.setState(
|
||||||
|
(state) => ({
|
||||||
|
messages: [
|
||||||
|
...state.messages,
|
||||||
|
{
|
||||||
|
id: String(Date.now()),
|
||||||
|
content: this.state.prompt,
|
||||||
|
role: "user",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
prompt: "",
|
||||||
|
isWaitingForResponse: true,
|
||||||
|
}),
|
||||||
|
() => {
|
||||||
|
const messages: Message[] = [...this.state.messages];
|
||||||
|
|
||||||
|
if (this.props.systemPrompt) {
|
||||||
|
messages.unshift({
|
||||||
|
id: String(Date.now()),
|
||||||
|
content: this.props.systemPrompt,
|
||||||
|
role: "system",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
messages,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.executeAction({
|
||||||
|
triggerPropertyName: "onClick",
|
||||||
|
dynamicString: `{{${this.props.queryRun}.run(${JSON.stringify(params)})}}`,
|
||||||
|
event: {
|
||||||
|
type: EventType.ON_CLICK,
|
||||||
|
callback: this.handleActionComplete,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleActionComplete = (result: ExecutionResult) => {
|
||||||
|
if (result.success) {
|
||||||
|
this.setState((state) => ({
|
||||||
|
messages: [
|
||||||
|
...state.messages,
|
||||||
|
{
|
||||||
|
id: Math.random().toString(),
|
||||||
|
content: this.props.queryData.choices[0].message.content,
|
||||||
|
role: "assistant",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isWaitingForResponse: false,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handlePromptChange = (prompt: string) => {
|
||||||
|
this.setState({ prompt });
|
||||||
|
};
|
||||||
|
|
||||||
|
getWidgetView(): ReactNode {
|
||||||
|
return (
|
||||||
|
<AIChat
|
||||||
|
assistantName={this.props.assistantName}
|
||||||
|
chatTitle={this.props.chatTitle}
|
||||||
|
description={this.props.description}
|
||||||
|
isWaitingForResponse={this.state.isWaitingForResponse}
|
||||||
|
onPromptChange={this.handlePromptChange}
|
||||||
|
onSubmit={this.handleMessageSubmit}
|
||||||
|
prompt={this.state.prompt}
|
||||||
|
promptInputPlaceholder={this.props.promptInputPlaceholder}
|
||||||
|
thread={this.adaptMessages(this.state.messages)}
|
||||||
|
username={this.props.username}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WDSAIChatWidget;
|
||||||
|
|
@ -59,6 +59,7 @@ export const WDS_V2_WIDGET_MAP = {
|
||||||
MULTILINE_INPUT_WIDGET: "WDS_MULTILINE_INPUT_WIDGET",
|
MULTILINE_INPUT_WIDGET: "WDS_MULTILINE_INPUT_WIDGET",
|
||||||
WDS_SELECT_WIDGET: "WDS_SELECT_WIDGET",
|
WDS_SELECT_WIDGET: "WDS_SELECT_WIDGET",
|
||||||
WDS_COMBOBOX_WIDGET: "WDS_COMBOBOX_WIDGET",
|
WDS_COMBOBOX_WIDGET: "WDS_COMBOBOX_WIDGET",
|
||||||
|
// WDS_AI_CHAT_WIDGET: "WDS_AI_CHAT_WIDGET",
|
||||||
|
|
||||||
// Anvil layout widgets
|
// Anvil layout widgets
|
||||||
ZONE_WIDGET: anvilWidgets.ZONE_WIDGET,
|
ZONE_WIDGET: anvilWidgets.ZONE_WIDGET,
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ import RangeSliderWidget from "./RangeSliderWidget";
|
||||||
import CategorySliderWidget from "./CategorySliderWidget";
|
import CategorySliderWidget from "./CategorySliderWidget";
|
||||||
import CodeScannerWidget from "./CodeScannerWidget";
|
import CodeScannerWidget from "./CodeScannerWidget";
|
||||||
import ListWidgetV2 from "./ListWidgetV2";
|
import ListWidgetV2 from "./ListWidgetV2";
|
||||||
|
import { WDSAIChatWidget } from "modules/ui-builder/ui/wds/WDSAIChatWidget";
|
||||||
import { WDSButtonWidget } from "modules/ui-builder/ui/wds/WDSButtonWidget";
|
import { WDSButtonWidget } from "modules/ui-builder/ui/wds/WDSButtonWidget";
|
||||||
import { WDSInputWidget } from "modules/ui-builder/ui/wds/WDSInputWidget";
|
import { WDSInputWidget } from "modules/ui-builder/ui/wds/WDSInputWidget";
|
||||||
import { WDSCheckboxWidget } from "modules/ui-builder/ui/wds/WDSCheckboxWidget";
|
import { WDSCheckboxWidget } from "modules/ui-builder/ui/wds/WDSCheckboxWidget";
|
||||||
|
|
@ -157,6 +158,7 @@ const DeprecatedWidgets = [
|
||||||
|
|
||||||
const WDSWidgets = [
|
const WDSWidgets = [
|
||||||
// WDS Widgets
|
// WDS Widgets
|
||||||
|
WDSAIChatWidget,
|
||||||
WDSButtonWidget,
|
WDSButtonWidget,
|
||||||
WDSInputWidget,
|
WDSInputWidget,
|
||||||
WDSCheckboxWidget,
|
WDSCheckboxWidget,
|
||||||
|
|
|
||||||
3
app/client/test/__mocks__/reactMarkdown.tsx
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
jest.mock("react-markdown", () => (props: { children: unknown }) => {
|
||||||
|
return <>{props.children}</>;
|
||||||
|
});
|
||||||