refactor: Enhance error handling, message editing and prompt display (#5310)
* 📝 (newChatMessage.tsx): add event listener to handle tab visibility change and update state accordingly 📝 (newChatMessage.tsx): remove event listener when component unmounts to prevent memory leaks * ✨ (use-tab-visibility.tsx): introduce custom hook useTabVisibility to track tab visibility changes in the browser 📝 (newChatMessage.tsx, newChatView.tsx): import and use useTabVisibility hook to handle tab visibility changes and update chat behavior accordingly * 📝 (newChatMessage.tsx): remove duplicate import of useTabVisibility and update import path 📝 (newChatView.tsx): remove duplicate import of useTabVisibility and update import path ✨ (use-tab-visibility.tsx): create a new custom hook to track tab visibility changes in the browser * reducing to smaller components * 📝 (frontend): remove unused imports and clean up code in various files to improve code readability and maintainability * 📝 (editMessage/index.tsx): Rename EditMessage component to MarkdownField for better clarity and consistency 📝 (newChatMessage.tsx): Replace EditMessage component with MarkdownField component for rendering chat messages with markdown support 📝 (newChatView.tsx): Add conditional rendering to display a message when no chat messages are fetched ✨ (chatViewWrapper/index.tsx): Add messageFetched prop to ChatView component to handle messages fetching status and improve component functionality. * prompt viedw * Refactor chat view component and remove unused prop * [autofix.ci] apply automated fixes --------- Co-authored-by: anovazzi1 <otavio2204@gmail.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
9a8f721515
commit
01c1d47ff5
13 changed files with 703 additions and 590 deletions
|
|
@ -1,6 +1,5 @@
|
|||
import IconComponent from "@/components/common/genericIconComponent";
|
||||
import ShadTooltip from "@/components/common/shadTooltipComponent";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Select,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,197 @@
|
|||
import { ForwardedIconComponent } from "@/components/common/genericIconComponent";
|
||||
import { TextShimmer } from "@/components/ui/TextShimmer";
|
||||
import { cn } from "@/utils/utils";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import Markdown from "react-markdown";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import CodeTabsComponent from "../../../../../../../components/core/codeTabsComponent/ChatCodeTabComponent";
|
||||
import LogoIcon from "../chatLogoIcon";
|
||||
|
||||
export const ErrorView = ({
|
||||
closeChat,
|
||||
fitViewNode,
|
||||
chat,
|
||||
showError,
|
||||
lastMessage,
|
||||
blocks,
|
||||
}: {
|
||||
blocks: any;
|
||||
showError: boolean;
|
||||
lastMessage: boolean;
|
||||
closeChat?: () => void;
|
||||
fitViewNode: (id: string) => void;
|
||||
chat: any;
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className="w-5/6 max-w-[768px] py-4 word-break-break-word">
|
||||
<AnimatePresence mode="wait">
|
||||
{!showError && lastMessage ? (
|
||||
<motion.div
|
||||
key="loading"
|
||||
initial={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="flex w-full gap-4 rounded-md p-2"
|
||||
>
|
||||
<LogoIcon />
|
||||
<div className="flex items-center">
|
||||
<TextShimmer className="" duration={1}>
|
||||
Flow running...
|
||||
</TextShimmer>
|
||||
</div>
|
||||
</motion.div>
|
||||
) : (
|
||||
<motion.div
|
||||
key="error"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className="flex w-full gap-4 rounded-md p-2"
|
||||
>
|
||||
<LogoIcon />
|
||||
{blocks.map((block, blockIndex) => (
|
||||
<div
|
||||
key={blockIndex}
|
||||
className="w-full rounded-xl border border-error-red-border bg-error-red p-4 text-[14px] text-foreground"
|
||||
>
|
||||
{block.contents.map((content, contentIndex) => {
|
||||
if (content.type === "error") {
|
||||
return (
|
||||
<div className="" key={contentIndex}>
|
||||
<div className="mb-2 flex items-center">
|
||||
<ForwardedIconComponent
|
||||
className="mr-2 h-[18px] w-[18px] text-destructive"
|
||||
name="OctagonAlert"
|
||||
/>
|
||||
{content.component && (
|
||||
<>
|
||||
<span>
|
||||
An error occured in the{" "}
|
||||
<span
|
||||
className={cn(
|
||||
closeChat ?? "cursor-pointer underline",
|
||||
)}
|
||||
onClick={() => {
|
||||
fitViewNode(
|
||||
chat.properties?.source?.id ?? "",
|
||||
);
|
||||
closeChat?.();
|
||||
}}
|
||||
>
|
||||
<strong>{content.component}</strong>
|
||||
</span>{" "}
|
||||
Component, stopping your flow. See below for
|
||||
more details.
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="pb-3 font-semibold">
|
||||
Error details:
|
||||
</h3>
|
||||
{content.field && (
|
||||
<p className="pb-1">Field: {content.field}</p>
|
||||
)}
|
||||
{content.reason && (
|
||||
<span className="">
|
||||
<Markdown
|
||||
linkTarget="_blank"
|
||||
remarkPlugins={[remarkGfm]}
|
||||
components={{
|
||||
a: ({ node, ...props }) => (
|
||||
<a
|
||||
href={props.href}
|
||||
target="_blank"
|
||||
className="underline"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{props.children}
|
||||
</a>
|
||||
),
|
||||
p({ node, ...props }) {
|
||||
return (
|
||||
<span className="inline-block w-fit max-w-full">
|
||||
{props.children}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
code: ({
|
||||
node,
|
||||
inline,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
let content = children as string;
|
||||
if (
|
||||
Array.isArray(children) &&
|
||||
children.length === 1 &&
|
||||
typeof children[0] === "string"
|
||||
) {
|
||||
content = children[0] as string;
|
||||
}
|
||||
if (typeof content === "string") {
|
||||
if (content.length) {
|
||||
if (content[0] === "▍") {
|
||||
return (
|
||||
<span className="form-modal-markdown-span"></span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const match = /language-(\w+)/.exec(
|
||||
className || "",
|
||||
);
|
||||
|
||||
return !inline ? (
|
||||
<CodeTabsComponent
|
||||
language={(match && match[1]) || ""}
|
||||
code={String(content).replace(
|
||||
/\n$/,
|
||||
"",
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<code
|
||||
className={className}
|
||||
{...props}
|
||||
>
|
||||
{content}
|
||||
</code>
|
||||
);
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
{content.reason}
|
||||
</Markdown>
|
||||
</span>
|
||||
)}
|
||||
{content.solution && (
|
||||
<div className="mt-4">
|
||||
<h3 className="pb-3 font-semibold">
|
||||
Steps to fix:
|
||||
</h3>
|
||||
<ol className="list-decimal pl-5">
|
||||
<li>Check the component settings</li>
|
||||
<li>Ensure all required fields are filled</li>
|
||||
<li>Re-run your flow</li>
|
||||
</ol>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
import { cn } from "@/utils/utils";
|
||||
|
||||
import { EMPTY_OUTPUT_SEND_MESSAGE } from "@/constants/constants";
|
||||
import Markdown from "react-markdown";
|
||||
import rehypeMathjax from "rehype-mathjax";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import CodeTabsComponent from "../../../../../../../components/core/codeTabsComponent/ChatCodeTabComponent";
|
||||
import EditMessageField from "../editMessageField";
|
||||
|
||||
type MarkdownFieldProps = {
|
||||
chat: any;
|
||||
isEmpty: boolean;
|
||||
chatMessage: string;
|
||||
editedFlag: React.ReactNode;
|
||||
};
|
||||
|
||||
export const MarkdownField = ({
|
||||
chat,
|
||||
isEmpty,
|
||||
chatMessage,
|
||||
editedFlag,
|
||||
}: MarkdownFieldProps) => {
|
||||
return (
|
||||
<div className="w-full items-baseline gap-2">
|
||||
<Markdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
linkTarget="_blank"
|
||||
rehypePlugins={[rehypeMathjax]}
|
||||
className={cn(
|
||||
"markdown prose flex w-fit max-w-full flex-col items-baseline text-[14px] font-normal word-break-break-word dark:prose-invert",
|
||||
isEmpty ? "text-muted-foreground" : "text-primary",
|
||||
)}
|
||||
components={{
|
||||
p({ node, ...props }) {
|
||||
return <span className="w-fit max-w-full">{props.children}</span>;
|
||||
},
|
||||
ol({ node, ...props }) {
|
||||
return <ol className="max-w-full">{props.children}</ol>;
|
||||
},
|
||||
ul({ node, ...props }) {
|
||||
return <ul className="max-w-full">{props.children}</ul>;
|
||||
},
|
||||
pre({ node, ...props }) {
|
||||
return <>{props.children}</>;
|
||||
},
|
||||
code: ({ node, inline, className, children, ...props }) => {
|
||||
let content = children as string;
|
||||
if (
|
||||
Array.isArray(children) &&
|
||||
children.length === 1 &&
|
||||
typeof children[0] === "string"
|
||||
) {
|
||||
content = children[0] as string;
|
||||
}
|
||||
if (typeof content === "string") {
|
||||
if (content.length) {
|
||||
if (content[0] === "▍") {
|
||||
return <span className="form-modal-markdown-span"></span>;
|
||||
}
|
||||
}
|
||||
|
||||
const match = /language-(\w+)/.exec(className || "");
|
||||
|
||||
return !inline ? (
|
||||
<CodeTabsComponent
|
||||
language={(match && match[1]) || ""}
|
||||
code={String(content).replace(/\n$/, "")}
|
||||
/>
|
||||
) : (
|
||||
<code className={className} {...props}>
|
||||
{content}
|
||||
</code>
|
||||
);
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
{isEmpty && !chat.stream_url ? EMPTY_OUTPUT_SEND_MESSAGE : chatMessage}
|
||||
</Markdown>
|
||||
{editedFlag}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
export const convertFiles = (
|
||||
files:
|
||||
| (
|
||||
| string
|
||||
| {
|
||||
path: string;
|
||||
type: string;
|
||||
name: string;
|
||||
}
|
||||
)[]
|
||||
| undefined,
|
||||
) => {
|
||||
if (!files) return [];
|
||||
return files.map((file) => {
|
||||
if (typeof file === "string") {
|
||||
return file;
|
||||
}
|
||||
return file.path;
|
||||
});
|
||||
};
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import { ProfileIcon } from "@/components/core/appHeaderComponent/components/ProfileIcon";
|
||||
import { ContentBlockDisplay } from "@/components/core/chatComponents/ContentBlockDisplay";
|
||||
import { TextShimmer } from "@/components/ui/TextShimmer";
|
||||
import { useUpdateMessage } from "@/controllers/API/queries/messages";
|
||||
import { CustomProfileIcon } from "@/customization/components/custom-profile-icon";
|
||||
import { ENABLE_DATASTAX_LANGFLOW } from "@/customization/feature-flags";
|
||||
|
|
@ -8,11 +7,7 @@ import useFlowsManagerStore from "@/stores/flowsManagerStore";
|
|||
import useFlowStore from "@/stores/flowStore";
|
||||
import { useUtilityStore } from "@/stores/utilityStore";
|
||||
import Convert from "ansi-to-html";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import Markdown from "react-markdown";
|
||||
import rehypeMathjax from "rehype-mathjax";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import Robot from "../../../../../assets/robot.png";
|
||||
import IconComponent, {
|
||||
ForwardedIconComponent,
|
||||
|
|
@ -27,10 +22,12 @@ import useTabVisibility from "../../../../../shared/hooks/use-tab-visibility";
|
|||
import useAlertStore from "../../../../../stores/alertStore";
|
||||
import { chatMessagePropsType } from "../../../../../types/components";
|
||||
import { cn } from "../../../../../utils/utils";
|
||||
import LogoIcon from "./components/chatLogoIcon";
|
||||
import { ErrorView } from "./components/contentView";
|
||||
import { MarkdownField } from "./components/editMessage";
|
||||
import { EditMessageButton } from "./components/editMessageButton/newMessageOptions";
|
||||
import EditMessageField from "./components/editMessageField/newEditMessageField";
|
||||
import FileCardWrapper from "./components/fileCardWrapper";
|
||||
import { convertFiles } from "./helpers/convert-files";
|
||||
|
||||
export default function ChatMessage({
|
||||
chat,
|
||||
|
|
@ -63,6 +60,7 @@ export default function ChatMessage({
|
|||
const chatMessageString = chat.message ? chat.message.toString() : "";
|
||||
setChatMessage(chatMessageString);
|
||||
}, [chat]);
|
||||
|
||||
const playgroundScrollBehaves = useUtilityStore(
|
||||
(state) => state.playgroundScrollBehaves,
|
||||
);
|
||||
|
|
@ -167,27 +165,6 @@ export default function ChatMessage({
|
|||
const isEmpty = decodedMessage?.trim() === "";
|
||||
const { mutate: updateMessageMutation } = useUpdateMessage();
|
||||
|
||||
const convertFiles = (
|
||||
files:
|
||||
| (
|
||||
| string
|
||||
| {
|
||||
path: string;
|
||||
type: string;
|
||||
name: string;
|
||||
}
|
||||
)[]
|
||||
| undefined,
|
||||
) => {
|
||||
if (!files) return [];
|
||||
return files.map((file) => {
|
||||
if (typeof file === "string") {
|
||||
return file;
|
||||
}
|
||||
return file.path;
|
||||
});
|
||||
};
|
||||
|
||||
const handleEditMessage = (message: string) => {
|
||||
updateMessageMutation(
|
||||
{
|
||||
|
|
@ -252,176 +229,14 @@ export default function ChatMessage({
|
|||
const blocks = chat.content_blocks ?? [];
|
||||
|
||||
return (
|
||||
<div className="w-5/6 max-w-[768px] py-4 word-break-break-word">
|
||||
<AnimatePresence mode="wait">
|
||||
{!showError && lastMessage ? (
|
||||
<motion.div
|
||||
key="loading"
|
||||
initial={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="flex w-full gap-4 rounded-md p-2"
|
||||
>
|
||||
<LogoIcon />
|
||||
<div className="flex items-center">
|
||||
<TextShimmer className="" duration={1}>
|
||||
Flow running...
|
||||
</TextShimmer>
|
||||
</div>
|
||||
</motion.div>
|
||||
) : (
|
||||
<motion.div
|
||||
key="error"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className="flex w-full gap-4 rounded-md p-2"
|
||||
>
|
||||
<LogoIcon />
|
||||
{blocks.map((block, blockIndex) => (
|
||||
<div
|
||||
key={blockIndex}
|
||||
className="w-full rounded-xl border border-error-red-border bg-error-red p-4 text-[14px] text-foreground"
|
||||
>
|
||||
{block.contents.map((content, contentIndex) => {
|
||||
if (content.type === "error") {
|
||||
return (
|
||||
<div className="" key={contentIndex}>
|
||||
<div className="mb-2 flex items-center">
|
||||
<ForwardedIconComponent
|
||||
className="mr-2 h-[18px] w-[18px] text-destructive"
|
||||
name="OctagonAlert"
|
||||
/>
|
||||
{content.component && (
|
||||
<>
|
||||
<span>
|
||||
An error occured in the{" "}
|
||||
<span
|
||||
className={cn(
|
||||
closeChat
|
||||
? "cursor-pointer underline"
|
||||
: "",
|
||||
)}
|
||||
onClick={() => {
|
||||
fitViewNode(
|
||||
chat.properties?.source?.id ?? "",
|
||||
);
|
||||
closeChat?.();
|
||||
}}
|
||||
>
|
||||
<strong>{content.component}</strong>
|
||||
</span>{" "}
|
||||
Component, stopping your flow. See below for
|
||||
more details.
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="pb-3 font-semibold">
|
||||
Error details:
|
||||
</h3>
|
||||
{content.field && (
|
||||
<p className="pb-1">Field: {content.field}</p>
|
||||
)}
|
||||
{content.reason && (
|
||||
<span className="">
|
||||
<Markdown
|
||||
linkTarget="_blank"
|
||||
remarkPlugins={[remarkGfm]}
|
||||
components={{
|
||||
a: ({ node, ...props }) => (
|
||||
<a
|
||||
href={props.href}
|
||||
target="_blank"
|
||||
className="underline"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{props.children}
|
||||
</a>
|
||||
),
|
||||
p({ node, ...props }) {
|
||||
return (
|
||||
<span className="inline-block w-fit max-w-full">
|
||||
{props.children}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
code: ({
|
||||
node,
|
||||
inline,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
let content = children as string;
|
||||
if (
|
||||
Array.isArray(children) &&
|
||||
children.length === 1 &&
|
||||
typeof children[0] === "string"
|
||||
) {
|
||||
content = children[0] as string;
|
||||
}
|
||||
if (typeof content === "string") {
|
||||
if (content.length) {
|
||||
if (content[0] === "▍") {
|
||||
return (
|
||||
<span className="form-modal-markdown-span"></span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const match = /language-(\w+)/.exec(
|
||||
className || "",
|
||||
);
|
||||
|
||||
return !inline ? (
|
||||
<CodeTabsComponent
|
||||
language={(match && match[1]) || ""}
|
||||
code={String(content).replace(
|
||||
/\n$/,
|
||||
"",
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<code
|
||||
className={className}
|
||||
{...props}
|
||||
>
|
||||
{content}
|
||||
</code>
|
||||
);
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
{content.reason}
|
||||
</Markdown>
|
||||
</span>
|
||||
)}
|
||||
{content.solution && (
|
||||
<div className="mt-4">
|
||||
<h3 className="pb-3 font-semibold">
|
||||
Steps to fix:
|
||||
</h3>
|
||||
<ol className="list-decimal pl-5">
|
||||
<li>Check the component settings</li>
|
||||
<li>Ensure all required fields are filled</li>
|
||||
<li>Re-run your flow</li>
|
||||
</ol>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
<ErrorView
|
||||
blocks={blocks}
|
||||
showError={showError}
|
||||
lastMessage={lastMessage}
|
||||
closeChat={closeChat}
|
||||
fitViewNode={fitViewNode}
|
||||
chat={chat}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -568,100 +383,12 @@ export default function ChatMessage({
|
|||
onCancel={() => setEditMessage(false)}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<div className="w-full items-baseline gap-2">
|
||||
<Markdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
linkTarget="_blank"
|
||||
rehypePlugins={[rehypeMathjax]}
|
||||
className={cn(
|
||||
"markdown prose flex w-fit max-w-full flex-col items-baseline text-[14px] font-normal word-break-break-word dark:prose-invert",
|
||||
isEmpty
|
||||
? "text-muted-foreground"
|
||||
: "text-primary",
|
||||
)}
|
||||
components={{
|
||||
p({ node, ...props }) {
|
||||
return (
|
||||
<span className="w-fit max-w-full">
|
||||
{props.children}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
ol({ node, ...props }) {
|
||||
return (
|
||||
<ol className="max-w-full">
|
||||
{props.children}
|
||||
</ol>
|
||||
);
|
||||
},
|
||||
ul({ node, ...props }) {
|
||||
return (
|
||||
<ul className="max-w-full">
|
||||
{props.children}
|
||||
</ul>
|
||||
);
|
||||
},
|
||||
pre({ node, ...props }) {
|
||||
return <>{props.children}</>;
|
||||
},
|
||||
code: ({
|
||||
node,
|
||||
inline,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
let content = children as string;
|
||||
if (
|
||||
Array.isArray(children) &&
|
||||
children.length === 1 &&
|
||||
typeof children[0] === "string"
|
||||
) {
|
||||
content = children[0] as string;
|
||||
}
|
||||
if (typeof content === "string") {
|
||||
if (content.length) {
|
||||
if (content[0] === "▍") {
|
||||
return (
|
||||
<span className="form-modal-markdown-span"></span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const match = /language-(\w+)/.exec(
|
||||
className || "",
|
||||
);
|
||||
|
||||
return !inline ? (
|
||||
<CodeTabsComponent
|
||||
language={
|
||||
(match && match[1]) || ""
|
||||
}
|
||||
code={String(content).replace(
|
||||
/\n$/,
|
||||
"",
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<code
|
||||
className={className}
|
||||
{...props}
|
||||
>
|
||||
{content}
|
||||
</code>
|
||||
);
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
{isEmpty && !chat.stream_url
|
||||
? EMPTY_OUTPUT_SEND_MESSAGE
|
||||
: chatMessage}
|
||||
</Markdown>
|
||||
{editedFlag}
|
||||
</div>
|
||||
</>
|
||||
<MarkdownField
|
||||
chat={chat}
|
||||
isEmpty={isEmpty}
|
||||
chatMessage={chatMessage}
|
||||
editedFlag={editedFlag}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -672,95 +399,37 @@ export default function ChatMessage({
|
|||
</div>
|
||||
) : (
|
||||
<div className="form-modal-chat-text-position flex-grow">
|
||||
{template ? (
|
||||
<>
|
||||
<button
|
||||
className="form-modal-initial-prompt-btn"
|
||||
onClick={() => {
|
||||
setPromptOpen((old) => !old);
|
||||
<div className="flex w-full flex-col">
|
||||
{editMessage ? (
|
||||
<EditMessageField
|
||||
key={`edit-message-${chat.id}`}
|
||||
message={decodedMessage}
|
||||
onEdit={(message) => {
|
||||
handleEditMessage(message);
|
||||
}}
|
||||
>
|
||||
Display Prompt
|
||||
<IconComponent
|
||||
name="ChevronDown"
|
||||
className={`h-3 w-3 transition-all ${promptOpen ? "rotate-180" : ""}`}
|
||||
/>
|
||||
</button>
|
||||
<span
|
||||
className={cn(
|
||||
"prose text-[14px] font-normal word-break-break-word dark:prose-invert",
|
||||
!isEmpty ? "text-primary" : "text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
{promptOpen
|
||||
? template?.split("\n")?.map((line, index) => {
|
||||
const regex = /{([^}]+)}/g;
|
||||
let match;
|
||||
let parts: Array<JSX.Element | string> = [];
|
||||
let lastIndex = 0;
|
||||
while ((match = regex.exec(line)) !== null) {
|
||||
// Push text up to the match
|
||||
if (match.index !== lastIndex) {
|
||||
parts.push(
|
||||
line.substring(lastIndex, match.index),
|
||||
);
|
||||
}
|
||||
// Push div with matched text
|
||||
if (chat.message[match[1]]) {
|
||||
parts.push(
|
||||
<span className="chat-message-highlight">
|
||||
{chat.message[match[1]]}
|
||||
</span>,
|
||||
);
|
||||
}
|
||||
|
||||
// Update last index
|
||||
lastIndex = regex.lastIndex;
|
||||
}
|
||||
// Push text after the last match
|
||||
if (lastIndex !== line.length) {
|
||||
parts.push(line.substring(lastIndex));
|
||||
}
|
||||
return <p>{parts}</p>;
|
||||
})
|
||||
: isEmpty
|
||||
? EMPTY_INPUT_SEND_MESSAGE
|
||||
: chatMessage}
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
<div className="flex w-full flex-col">
|
||||
{editMessage ? (
|
||||
<EditMessageField
|
||||
key={`edit-message-${chat.id}`}
|
||||
message={decodedMessage}
|
||||
onEdit={(message) => {
|
||||
handleEditMessage(message);
|
||||
}}
|
||||
onCancel={() => setEditMessage(false)}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
className={`w-full items-baseline whitespace-pre-wrap break-words text-[14px] font-normal ${
|
||||
isEmpty ? "text-muted-foreground" : "text-primary"
|
||||
}`}
|
||||
data-testid={`chat-message-${chat.sender_name}-${chatMessage}`}
|
||||
>
|
||||
{isEmpty ? EMPTY_INPUT_SEND_MESSAGE : decodedMessage}
|
||||
{editedFlag}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{chat.files && (
|
||||
<div className="my-2 flex flex-col gap-5">
|
||||
{chat.files?.map((file, index) => {
|
||||
return <FileCardWrapper index={index} path={file} />;
|
||||
})}
|
||||
onCancel={() => setEditMessage(false)}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
className={`w-full items-baseline whitespace-pre-wrap break-words text-[14px] font-normal ${
|
||||
isEmpty ? "text-muted-foreground" : "text-primary"
|
||||
}`}
|
||||
data-testid={`chat-message-${chat.sender_name}-${chatMessage}`}
|
||||
>
|
||||
{isEmpty ? EMPTY_INPUT_SEND_MESSAGE : decodedMessage}
|
||||
{editedFlag}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{chat.files && (
|
||||
<div className="my-2 flex flex-col gap-5">
|
||||
{chat.files?.map((file, index) => {
|
||||
return <FileCardWrapper index={index} path={file} />;
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -91,8 +91,8 @@ export default function ChatView({
|
|||
|
||||
if (messages.length === 0 && !lockChat && chatInputNode) {
|
||||
setChatValue(chatInputNode.data.node.template["input_value"].value ?? "");
|
||||
} else if (isTabHidden) {
|
||||
setChatValue("");
|
||||
} else {
|
||||
isTabHidden ? setChatValue("") : null;
|
||||
}
|
||||
|
||||
setChatHistory(finalChatHistory);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
import ShadTooltip from "@/components/common/shadTooltipComponent";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { cn } from "@/utils/utils";
|
||||
import IconComponent from "../../../../components/common/genericIconComponent";
|
||||
import { ChatViewWrapperProps } from "../../types/chat-view-wrapper";
|
||||
import ChatView from "../chatView/newChatView";
|
||||
|
||||
export const ChatViewWrapper = ({
|
||||
selectedViewField,
|
||||
visibleSession,
|
||||
sessions,
|
||||
sidebarOpen,
|
||||
currentFlowId,
|
||||
setSidebarOpen,
|
||||
isPlayground,
|
||||
setvisibleSession,
|
||||
setSelectedViewField,
|
||||
messagesFetched,
|
||||
sessionId,
|
||||
sendMessage,
|
||||
chatValue,
|
||||
setChatValue,
|
||||
lockChat,
|
||||
setLockChat,
|
||||
canvasOpen,
|
||||
setOpen,
|
||||
}: ChatViewWrapperProps) => {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"flex h-full w-full flex-col justify-between p-4",
|
||||
selectedViewField ? "hidden" : "",
|
||||
)}
|
||||
>
|
||||
<div className="mb-4 h-[5%] text-[16px] font-semibold">
|
||||
{visibleSession && sessions.length > 0 && sidebarOpen && (
|
||||
<div className="hidden lg:block">
|
||||
{visibleSession === currentFlowId
|
||||
? "Default Session"
|
||||
: `${visibleSession}`}
|
||||
</div>
|
||||
)}
|
||||
<div className={cn(sidebarOpen ? "lg:hidden" : "")}>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setSidebarOpen(true)}
|
||||
className="h-8 w-8"
|
||||
>
|
||||
<IconComponent
|
||||
name="PanelLeftOpen"
|
||||
className="h-[18px] w-[18px] text-ring"
|
||||
/>
|
||||
</Button>
|
||||
<div className="font-semibold">Playground</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
sidebarOpen ? "pointer-events-none opacity-0" : "",
|
||||
"absolute flex h-8 items-center justify-center rounded-sm ring-offset-background transition-opacity focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
isPlayground ? "right-2 top-4" : "right-12 top-2",
|
||||
)}
|
||||
>
|
||||
<ShadTooltip side="bottom" styleClasses="z-50" content="New Chat">
|
||||
<Button
|
||||
className="mr-2 h-[32px] w-[32px] hover:bg-secondary-hover"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => {
|
||||
setvisibleSession(undefined);
|
||||
setSelectedViewField(undefined);
|
||||
}}
|
||||
>
|
||||
<IconComponent
|
||||
name="Plus"
|
||||
className="!h-[18px] !w-[18px] text-ring"
|
||||
/>
|
||||
</Button>
|
||||
</ShadTooltip>
|
||||
{!isPlayground && <Separator orientation="vertical" />}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
visibleSession ? "h-[95%]" : "h-full",
|
||||
sidebarOpen
|
||||
? "pointer-events-none blur-sm lg:pointer-events-auto lg:blur-0"
|
||||
: "",
|
||||
)}
|
||||
>
|
||||
{messagesFetched && (
|
||||
<ChatView
|
||||
focusChat={sessionId}
|
||||
sendMessage={sendMessage}
|
||||
chatValue={chatValue}
|
||||
setChatValue={setChatValue}
|
||||
lockChat={lockChat}
|
||||
setLockChat={setLockChat}
|
||||
visibleSession={visibleSession}
|
||||
closeChat={
|
||||
!canvasOpen
|
||||
? undefined
|
||||
: () => {
|
||||
setOpen(false);
|
||||
}
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
import { InputOutput } from "@/constants/enums";
|
||||
import { cn } from "@/utils/utils";
|
||||
import IconComponent from "../../../../components/common/genericIconComponent";
|
||||
import { SelectedViewFieldProps } from "../../types/selected-view-field";
|
||||
import IOFieldView from "../IOFieldView";
|
||||
import SessionView from "../SessionView";
|
||||
|
||||
export const SelectedViewField = ({
|
||||
selectedViewField,
|
||||
setSelectedViewField,
|
||||
haveChat,
|
||||
inputs,
|
||||
outputs,
|
||||
sessions,
|
||||
currentFlowId,
|
||||
nodes,
|
||||
}: SelectedViewFieldProps) => {
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={cn(
|
||||
"flex h-full w-full flex-col items-start gap-4 p-4",
|
||||
!selectedViewField ? "hidden" : "",
|
||||
)}
|
||||
>
|
||||
<div className="font-xl flex items-center justify-center gap-3 font-semibold">
|
||||
{haveChat && (
|
||||
<button onClick={() => setSelectedViewField(undefined)}>
|
||||
<IconComponent
|
||||
name={"ArrowLeft"}
|
||||
className="h-6 w-6"
|
||||
></IconComponent>
|
||||
</button>
|
||||
)}
|
||||
{
|
||||
nodes.find((node) => node.id === selectedViewField?.id)?.data.node
|
||||
.display_name
|
||||
}
|
||||
</div>
|
||||
<div className="h-full w-full">
|
||||
{inputs.some((input) => input.id === selectedViewField?.id) && (
|
||||
<IOFieldView
|
||||
type={InputOutput.INPUT}
|
||||
left={false}
|
||||
fieldType={selectedViewField?.type!}
|
||||
fieldId={selectedViewField?.id!}
|
||||
/>
|
||||
)}
|
||||
{outputs.some((output) => output.id === selectedViewField?.id) && (
|
||||
<IOFieldView
|
||||
type={InputOutput.OUTPUT}
|
||||
left={false}
|
||||
fieldType={selectedViewField?.type!}
|
||||
fieldId={selectedViewField?.id!}
|
||||
/>
|
||||
)}
|
||||
{sessions.some((session) => session === selectedViewField?.id) && (
|
||||
<SessionView session={selectedViewField?.id} id={currentFlowId} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
import ShadTooltip from "@/components/common/shadTooltipComponent";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import IconComponent from "../../../../components/common/genericIconComponent";
|
||||
import { SidebarOpenViewProps } from "../../types/sidebar-open-view";
|
||||
import SessionSelector from "../IOFieldView/components/sessionSelector/newSessionSelector";
|
||||
|
||||
export const SidebarOpenView = ({
|
||||
sessions,
|
||||
setSelectedViewField,
|
||||
setvisibleSession,
|
||||
handleDeleteSession,
|
||||
visibleSession,
|
||||
selectedViewField,
|
||||
}: SidebarOpenViewProps) => {
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col pl-3">
|
||||
<div className="flex flex-col gap-2 pb-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<IconComponent
|
||||
name="MessagesSquare"
|
||||
className="h-[18px] w-[18px] text-ring"
|
||||
/>
|
||||
<div className="text-[13px] font-normal">Chat</div>
|
||||
</div>
|
||||
<ShadTooltip styleClasses="z-50" content="New Chat">
|
||||
<div>
|
||||
<Button
|
||||
data-testid="new-chat"
|
||||
variant="ghost"
|
||||
className="flex h-8 w-8 items-center justify-center !p-0 hover:bg-secondary-hover"
|
||||
onClick={(_) => {
|
||||
setvisibleSession(undefined);
|
||||
setSelectedViewField(undefined);
|
||||
}}
|
||||
>
|
||||
<IconComponent
|
||||
name="Plus"
|
||||
className="h-[18px] w-[18px] text-ring"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
</ShadTooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
{sessions.map((session, index) => (
|
||||
<SessionSelector
|
||||
setSelectedView={setSelectedViewField}
|
||||
selectedView={selectedViewField}
|
||||
key={index}
|
||||
session={session}
|
||||
deleteSession={(session) => {
|
||||
handleDeleteSession(session);
|
||||
if (selectedViewField?.id === session) {
|
||||
setSelectedViewField(undefined);
|
||||
}
|
||||
}}
|
||||
updateVisibleSession={(session) => {
|
||||
setvisibleSession(session);
|
||||
}}
|
||||
toggleVisibility={() => {
|
||||
setvisibleSession(session);
|
||||
}}
|
||||
isVisible={visibleSession === session}
|
||||
inspectSession={(session) => {
|
||||
setSelectedViewField({
|
||||
id: session,
|
||||
type: "Session",
|
||||
});
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
@ -8,7 +8,6 @@ import { useCallback, useEffect, useState } from "react";
|
|||
import IconComponent from "../../components/common/genericIconComponent";
|
||||
import ShadTooltip from "../../components/common/shadTooltipComponent";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { InputOutput } from "../../constants/enums";
|
||||
import useAlertStore from "../../stores/alertStore";
|
||||
import useFlowStore from "../../stores/flowStore";
|
||||
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
||||
|
|
@ -16,10 +15,10 @@ import { useMessagesStore } from "../../stores/messagesStore";
|
|||
import { IOModalPropsType } from "../../types/components";
|
||||
import { cn } from "../../utils/utils";
|
||||
import BaseModal from "../baseModal";
|
||||
import IOFieldView from "./components/IOFieldView";
|
||||
import SessionSelector from "./components/IOFieldView/components/sessionSelector/newSessionSelector";
|
||||
import SessionView from "./components/SessionView";
|
||||
import ChatView from "./components/chatView/newChatView";
|
||||
import { ChatViewWrapper } from "./components/chatViewWrapper";
|
||||
import { SelectedViewField } from "./components/selectedViewField";
|
||||
import { SidebarOpenView } from "./components/sidebarOpenView";
|
||||
|
||||
export default function IOModal({
|
||||
children,
|
||||
|
|
@ -292,217 +291,51 @@ export default function IOModal({
|
|||
)}
|
||||
</div>
|
||||
{sidebarOpen && (
|
||||
<div className="flex flex-col pl-3">
|
||||
<div className="flex flex-col gap-2 pb-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<IconComponent
|
||||
name="MessagesSquare"
|
||||
className="h-[18px] w-[18px] text-ring"
|
||||
/>
|
||||
<div className="text-[13px] font-normal">Chat</div>
|
||||
</div>
|
||||
<ShadTooltip styleClasses="z-50" content="New Chat">
|
||||
<div>
|
||||
<Button
|
||||
data-testid="new-chat"
|
||||
variant="ghost"
|
||||
className="flex h-8 w-8 items-center justify-center !p-0 hover:bg-secondary-hover"
|
||||
onClick={(_) => {
|
||||
setvisibleSession(undefined);
|
||||
setSelectedViewField(undefined);
|
||||
}}
|
||||
>
|
||||
<IconComponent
|
||||
name="Plus"
|
||||
className="h-[18px] w-[18px] text-ring"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
</ShadTooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
{sessions.map((session, index) => (
|
||||
<SessionSelector
|
||||
setSelectedView={setSelectedViewField}
|
||||
selectedView={selectedViewField}
|
||||
key={index}
|
||||
session={session}
|
||||
deleteSession={(session) => {
|
||||
handleDeleteSession(session);
|
||||
if (selectedViewField?.id === session) {
|
||||
setSelectedViewField(undefined);
|
||||
}
|
||||
}}
|
||||
updateVisibleSession={(session) => {
|
||||
setvisibleSession(session);
|
||||
}}
|
||||
toggleVisibility={() => {
|
||||
setvisibleSession(session);
|
||||
}}
|
||||
isVisible={visibleSession === session}
|
||||
inspectSession={(session) => {
|
||||
setSelectedViewField({
|
||||
id: session,
|
||||
type: "Session",
|
||||
});
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<SidebarOpenView
|
||||
sessions={sessions}
|
||||
setSelectedViewField={setSelectedViewField}
|
||||
setvisibleSession={setvisibleSession}
|
||||
handleDeleteSession={handleDeleteSession}
|
||||
visibleSession={visibleSession}
|
||||
selectedViewField={selectedViewField}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex h-full min-w-96 flex-grow bg-background">
|
||||
{selectedViewField && (
|
||||
<div
|
||||
className={cn(
|
||||
"flex h-full w-full flex-col items-start gap-4 p-4",
|
||||
!selectedViewField ? "hidden" : "",
|
||||
)}
|
||||
>
|
||||
<div className="font-xl flex items-center justify-center gap-3 font-semibold">
|
||||
{haveChat && (
|
||||
<button onClick={() => setSelectedViewField(undefined)}>
|
||||
<IconComponent
|
||||
name={"ArrowLeft"}
|
||||
className="h-6 w-6"
|
||||
></IconComponent>
|
||||
</button>
|
||||
)}
|
||||
{
|
||||
nodes.find((node) => node.id === selectedViewField.id)
|
||||
?.data.node.display_name
|
||||
}
|
||||
</div>
|
||||
<div className="h-full w-full">
|
||||
{inputs.some(
|
||||
(input) => input.id === selectedViewField.id,
|
||||
) && (
|
||||
<IOFieldView
|
||||
type={InputOutput.INPUT}
|
||||
left={false}
|
||||
fieldType={selectedViewField.type!}
|
||||
fieldId={selectedViewField.id!}
|
||||
/>
|
||||
)}
|
||||
{outputs.some(
|
||||
(output) => output.id === selectedViewField.id,
|
||||
) && (
|
||||
<IOFieldView
|
||||
type={InputOutput.OUTPUT}
|
||||
left={false}
|
||||
fieldType={selectedViewField.type!}
|
||||
fieldId={selectedViewField.id!}
|
||||
/>
|
||||
)}
|
||||
{sessions.some(
|
||||
(session) => session === selectedViewField.id,
|
||||
) && (
|
||||
<SessionView
|
||||
session={selectedViewField.id}
|
||||
id={currentFlowId}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<SelectedViewField
|
||||
selectedViewField={selectedViewField}
|
||||
setSelectedViewField={setSelectedViewField}
|
||||
haveChat={haveChat}
|
||||
inputs={inputs}
|
||||
outputs={outputs}
|
||||
sessions={sessions}
|
||||
currentFlowId={currentFlowId}
|
||||
nodes={nodes}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className={cn(
|
||||
"flex h-full w-full flex-col justify-between p-4",
|
||||
selectedViewField ? "hidden" : "",
|
||||
)}
|
||||
>
|
||||
<div className="mb-4 h-[5%] text-[16px] font-semibold">
|
||||
{visibleSession && sessions.length > 0 && sidebarOpen && (
|
||||
<div className="hidden lg:block">
|
||||
{visibleSession === currentFlowId
|
||||
? "Default Session"
|
||||
: `${visibleSession}`}
|
||||
</div>
|
||||
)}
|
||||
<div className={cn(sidebarOpen ? "lg:hidden" : "")}>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setSidebarOpen(true)}
|
||||
className="h-8 w-8"
|
||||
>
|
||||
<IconComponent
|
||||
name={"PanelLeftOpen"}
|
||||
className="h-[18px] w-[18px] text-ring"
|
||||
/>
|
||||
</Button>
|
||||
<div className="font-semibold">Playground</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
sidebarOpen ? "pointer-events-none opacity-0" : "",
|
||||
"absolute flex h-8 items-center justify-center rounded-sm ring-offset-background transition-opacity focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
isPlayground ? "right-2 top-4" : "right-12 top-2",
|
||||
)}
|
||||
>
|
||||
<ShadTooltip
|
||||
side="bottom"
|
||||
styleClasses="z-50"
|
||||
content="New Chat"
|
||||
>
|
||||
<Button
|
||||
className="mr-2 h-[32px] w-[32px] hover:bg-secondary-hover"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={(_) => {
|
||||
setvisibleSession(undefined);
|
||||
setSelectedViewField(undefined);
|
||||
}}
|
||||
>
|
||||
<IconComponent
|
||||
name="Plus"
|
||||
className="!h-[18px] !w-[18px] text-ring"
|
||||
/>
|
||||
</Button>
|
||||
</ShadTooltip>
|
||||
{!isPlayground && <Separator orientation="vertical" />}
|
||||
</div>
|
||||
</div>
|
||||
{haveChat ? (
|
||||
<div
|
||||
className={cn(
|
||||
visibleSession ? "h-[95%]" : "h-full",
|
||||
sidebarOpen
|
||||
? "pointer-events-none blur-sm lg:pointer-events-auto lg:blur-0"
|
||||
: "",
|
||||
)}
|
||||
>
|
||||
{messagesFetched && (
|
||||
<ChatView
|
||||
focusChat={sessionId}
|
||||
sendMessage={sendMessage}
|
||||
chatValue={chatValue}
|
||||
setChatValue={setChatValue}
|
||||
lockChat={lockChat}
|
||||
setLockChat={setLockChat}
|
||||
visibleSession={visibleSession}
|
||||
closeChat={
|
||||
!canvasOpen
|
||||
? undefined
|
||||
: () => {
|
||||
setOpen(false);
|
||||
}
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<span className="flex h-full w-full items-center justify-center font-thin text-muted-foreground">
|
||||
Select an IO component to view
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<ChatViewWrapper
|
||||
selectedViewField={selectedViewField}
|
||||
visibleSession={visibleSession}
|
||||
sessions={sessions}
|
||||
sidebarOpen={sidebarOpen}
|
||||
currentFlowId={currentFlowId}
|
||||
setSidebarOpen={setSidebarOpen}
|
||||
isPlayground={isPlayground}
|
||||
setvisibleSession={setvisibleSession}
|
||||
setSelectedViewField={setSelectedViewField}
|
||||
haveChat={haveChat}
|
||||
messagesFetched={messagesFetched}
|
||||
sessionId={sessionId}
|
||||
sendMessage={sendMessage}
|
||||
chatValue={chatValue}
|
||||
setChatValue={setChatValue}
|
||||
lockChat={lockChat}
|
||||
setLockChat={setLockChat}
|
||||
canvasOpen={canvasOpen}
|
||||
setOpen={setOpen}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
23
src/frontend/src/modals/IOModal/types/chat-view-wrapper.ts
Normal file
23
src/frontend/src/modals/IOModal/types/chat-view-wrapper.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
export type ChatViewWrapperProps = {
|
||||
selectedViewField: { type: string; id: string } | undefined;
|
||||
visibleSession: string | undefined;
|
||||
sessions: string[];
|
||||
sidebarOpen: boolean;
|
||||
currentFlowId: string;
|
||||
setSidebarOpen: (open: boolean) => void;
|
||||
isPlayground: boolean | undefined;
|
||||
setvisibleSession: (session: string | undefined) => void;
|
||||
setSelectedViewField: (
|
||||
field: { type: string; id: string } | undefined,
|
||||
) => void;
|
||||
haveChat: { type: string; id: string; displayName: string } | undefined;
|
||||
messagesFetched: boolean;
|
||||
sessionId: string;
|
||||
sendMessage: (options: { repeat: number; files?: string[] }) => Promise<void>;
|
||||
chatValue: string;
|
||||
setChatValue: (value: string) => void;
|
||||
lockChat: boolean;
|
||||
setLockChat: (locked: boolean) => void;
|
||||
canvasOpen: boolean | undefined;
|
||||
setOpen: (open: boolean) => void;
|
||||
};
|
||||
21
src/frontend/src/modals/IOModal/types/selected-view-field.ts
Normal file
21
src/frontend/src/modals/IOModal/types/selected-view-field.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { Node } from "reactflow";
|
||||
export type SelectedViewFieldProps = {
|
||||
selectedViewField: { type: string; id: string } | undefined;
|
||||
setSelectedViewField: (
|
||||
field: { type: string; id: string } | undefined,
|
||||
) => void;
|
||||
haveChat: { type: string; id: string; displayName: string } | undefined;
|
||||
inputs: Array<{
|
||||
type: string;
|
||||
id: string;
|
||||
displayName: string;
|
||||
}>;
|
||||
outputs: Array<{
|
||||
type: string;
|
||||
id: string;
|
||||
displayName: string;
|
||||
}>;
|
||||
sessions: string[];
|
||||
currentFlowId: string;
|
||||
nodes: Node[];
|
||||
};
|
||||
10
src/frontend/src/modals/IOModal/types/sidebar-open-view.ts
Normal file
10
src/frontend/src/modals/IOModal/types/sidebar-open-view.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export type SidebarOpenViewProps = {
|
||||
sessions: string[];
|
||||
setSelectedViewField: (
|
||||
field: { type: string; id: string } | undefined,
|
||||
) => void;
|
||||
setvisibleSession: (session: string | undefined) => void;
|
||||
handleDeleteSession: (session: string) => void;
|
||||
visibleSession: string | undefined;
|
||||
selectedViewField: { type: string; id: string } | undefined;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue