Fix formatting issues in code

This commit is contained in:
anovazzi1 2024-01-18 16:48:13 -03:00
commit 65ec1ab3a5
21 changed files with 841 additions and 859 deletions

View file

@ -67,7 +67,9 @@ Human: {input}
class MidJourneyPromptChain(BaseCustomConversationChain): class MidJourneyPromptChain(BaseCustomConversationChain):
"""MidJourneyPromptChain is a chain you can use to generate new MidJourney prompts.""" """MidJourneyPromptChain is a chain you can use to generate new MidJourney prompts."""
template: Optional[str] = """I want you to act as a prompt generator for Midjourney's artificial intelligence program. template: Optional[
str
] = """I want you to act as a prompt generator for Midjourney's artificial intelligence program.
Your job is to provide detailed and creative descriptions that will inspire unique and interesting images from the AI. Your job is to provide detailed and creative descriptions that will inspire unique and interesting images from the AI.
Keep in mind that the AI is capable of understanding a wide range of language and can interpret abstract concepts, so feel free to be as imaginative and descriptive as possible. Keep in mind that the AI is capable of understanding a wide range of language and can interpret abstract concepts, so feel free to be as imaginative and descriptive as possible.
For example, you could describe a scene from a futuristic city, or a surreal landscape filled with strange creatures. For example, you could describe a scene from a futuristic city, or a surreal landscape filled with strange creatures.
@ -81,7 +83,9 @@ class MidJourneyPromptChain(BaseCustomConversationChain):
class TimeTravelGuideChain(BaseCustomConversationChain): class TimeTravelGuideChain(BaseCustomConversationChain):
template: Optional[str] = """I want you to act as my time travel guide. You are helpful and creative. I will provide you with the historical period or future time I want to visit and you will suggest the best events, sights, or people to experience. Provide the suggestions and any necessary information. template: Optional[
str
] = """I want you to act as my time travel guide. You are helpful and creative. I will provide you with the historical period or future time I want to visit and you will suggest the best events, sights, or people to experience. Provide the suggestions and any necessary information.
Current conversation: Current conversation:
{history} {history}
Human: {input} Human: {input}

View file

@ -23,7 +23,6 @@ import useFlowsManagerStore from "./stores/flowsManagerStore";
import { useTypesStore } from "./stores/typesStore"; import { useTypesStore } from "./stores/typesStore";
export default function App() { export default function App() {
const errorData = useAlertStore((state) => state.errorData); const errorData = useAlertStore((state) => state.errorData);
const errorOpen = useAlertStore((state) => state.errorOpen); const errorOpen = useAlertStore((state) => state.errorOpen);
const setErrorOpen = useAlertStore((state) => state.setErrorOpen); const setErrorOpen = useAlertStore((state) => state.setErrorOpen);

View file

@ -131,25 +131,24 @@ export default function ParameterComponent({
if (data.node!.template[name].value !== code) { if (data.node!.template[name].value !== code) {
takeSnapshot(); takeSnapshot();
} }
setNode(data.id, (oldNode) => { setNode(data.id, (oldNode) => {
let newNode = cloneDeep(oldNode); let newNode = cloneDeep(oldNode);
newNode.data = { newNode.data = {
...newNode.data, ...newNode.data,
node: newNodeClass, node: newNodeClass,
description: newNodeClass.description ?? data.node!.description, description: newNodeClass.description ?? data.node!.description,
display_name: newNodeClass.display_name ?? data.node!.display_name, display_name: newNodeClass.display_name ?? data.node!.display_name,
}; };
newNode.data.node.template[name].value = code; newNode.data.node.template[name].value = code;
return newNode; return newNode;
}); });
updateNodeInternals(data.id); updateNodeInternals(data.id);
renderTooltips(); renderTooltips();
}; };
@ -273,9 +272,11 @@ export default function ParameterComponent({
<Handle <Handle
type={left ? "target" : "source"} type={left ? "target" : "source"}
position={left ? Position.Left : Position.Right} position={left ? Position.Left : Position.Right}
key={proxy key={
? scapedJSONStringfy({ ...id, proxy }) proxy
: scapedJSONStringfy(id)} ? scapedJSONStringfy({ ...id, proxy })
: scapedJSONStringfy(id)
}
id={ id={
proxy proxy
? scapedJSONStringfy({ ...id, proxy }) ? scapedJSONStringfy({ ...id, proxy })
@ -348,9 +349,11 @@ export default function ParameterComponent({
<Handle <Handle
type={left ? "target" : "source"} type={left ? "target" : "source"}
position={left ? Position.Left : Position.Right} position={left ? Position.Left : Position.Right}
key={proxy key={
? scapedJSONStringfy({ ...id, proxy }) proxy
: scapedJSONStringfy(id)} ? scapedJSONStringfy({ ...id, proxy })
: scapedJSONStringfy(id)
}
id={ id={
proxy proxy
? scapedJSONStringfy({ ...id, proxy }) ? scapedJSONStringfy({ ...id, proxy })

View file

@ -1,93 +1,92 @@
import { ReactNode, useContext, useState } from "react"; import { ReactNode, useState } from "react";
import NewChatView from "../newChatView";
import { extractTypeFromLongId, removeCountFromString } from "../../utils/utils";
import AccordionComponent from "../AccordionComponent";
import { Badge } from "../ui/badge";
import ShadTooltip from "../ShadTooltipComponent";
import IconComponent from "../genericIconComponent";
import { Textarea } from "../ui/textarea";
import { NodeDataType } from "../../types/flow";
import useFlowStore from "../../stores/flowStore"; import useFlowStore from "../../stores/flowStore";
import useFlowsManagerStore from "../../stores/flowsManagerStore";
import useFlowIOStore from "../../stores/flowsIOStore"; import useFlowIOStore from "../../stores/flowsIOStore";
import { NodeDataType } from "../../types/flow";
import { extractTypeFromLongId } from "../../utils/utils";
import AccordionComponent from "../AccordionComponent";
import IconComponent from "../genericIconComponent";
import NewChatView from "../newChatView";
import { Badge } from "../ui/badge";
import { Textarea } from "../ui/textarea";
export default function IOView(): JSX.Element { export default function IOView(): JSX.Element {
const {inputIds, outputIds, updateNodeFlowData } = const { inputIds, outputIds, updateNodeFlowData } = useFlowIOStore();
useFlowIOStore(); const { reactFlowInstance } = useFlowStore();
const { reactFlowInstance } = useFlowStore(); const options = inputIds.concat(outputIds);
const options = inputIds.concat(outputIds); const [selectedView, setSelectedView] = useState<ReactNode>(
const [selectedView, setSelectedView] = useState<ReactNode>(handleSelectChange(options[0])); handleSelectChange(options[0])
// if (outputTypes.includes("ChatOutput")) { );
// return <NewChatView />; // if (outputTypes.includes("ChatOutput")) {
// } // return <NewChatView />;
function handleSelectChange(selected: string) { // }
const type = extractTypeFromLongId(selected); function handleSelectChange(selected: string) {
return <NewChatView /> const type = extractTypeFromLongId(selected);
switch (type) { return <NewChatView />;
case "ChatOutput": switch (type) {
return <NewChatView />; case "ChatOutput":
break; return <NewChatView />;
} break;
} }
}
return (
return ( <div className="form-modal-iv-box">
<div className="form-modal-iv-box"> <div className="mr-6 flex h-full w-2/6 flex-col justify-start overflow-auto scrollbar-hide">
<div className="mr-6 flex h-full w-2/6 flex-col justify-start overflow-auto scrollbar-hide"> <div className="file-component-arrangement">
<div className="file-component-arrangement"> <IconComponent name="Variable" className=" file-component-variable" />
<IconComponent <span className="file-component-variables-span text-md">Inputs</span>
name="Variable" </div>
className=" file-component-variable" {inputIds
/> .filter((input) => extractTypeFromLongId(input) !== "ChatInput")
<span className="file-component-variables-span text-md"> .map((inputId, index) => {
Inputs const nodeData: NodeDataType = reactFlowInstance
</span> ?.getNodes()
</div> .find((node) => node.id === inputId)?.data;
{ return (
inputIds.filter(input=>extractTypeFromLongId(input)!=="ChatInput").map((inputId,index) => { <div className="file-component-accordion-div" key={index}>
const nodeData:NodeDataType = reactFlowInstance?.getNodes().find(node=>node.id===inputId)?.data; <AccordionComponent
return ( trigger={
<div className="file-component-accordion-div" key={index}> <div className="file-component-badge-div">
<AccordionComponent <Badge variant="gray" size="md">
trigger={ {inputId}
<div className="file-component-badge-div"> </Badge>
<Badge variant="gray" size="md"> <div
{inputId} className="-mb-1"
</Badge> onClick={(event) => {
<div event.stopPropagation();
className="-mb-1" }}
onClick={(event) => { ></div>
event.stopPropagation(); </div>
}} }
> key={index}
</div> keyValue={inputId}
</div> >
} <div className="file-component-tab-column">
key={index} <Textarea
keyValue={inputId} value={
> reactFlowInstance
<div className="file-component-tab-column"> ?.getNodes()
<Textarea .find((node) => node.id === inputId)?.data?.node
value={reactFlowInstance?.getNodes().find(node=>node.id===inputId)?.data?.node?.template?.value.value} ?.template?.value.value
className="custom-scroll" }
onChange={(e) => { className="custom-scroll"
e.target.value; onChange={(e) => {
if(nodeData){ e.target.value;
nodeData.node!.template["value"].value = e.target.value; if (nodeData) {
updateNodeFlowData(inputId,nodeData); nodeData.node!.template["value"].value =
} e.target.value;
}} updateNodeFlowData(inputId, nodeData);
placeholder="Enter text..." }
></Textarea> }}
</div> placeholder="Enter text..."
</AccordionComponent> ></Textarea>
</div> </div>
) </AccordionComponent>
}) </div>
} );
</div> })}
{selectedView} </div>
</div> {selectedView}
); </div>
);
} }

View file

@ -5,123 +5,121 @@ import { chatInputType } from "../../../types/components";
import { classNames } from "../../../utils/utils"; import { classNames } from "../../../utils/utils";
export default function ChatInput({ export default function ChatInput({
lockChat, lockChat,
chatValue, chatValue,
sendMessage, sendMessage,
setChatValue, setChatValue,
inputRef, inputRef,
noInput, noInput,
}: chatInputType): JSX.Element { }: chatInputType): JSX.Element {
const [repeate, setRepeate] = useState(1); const [repeate, setRepeate] = useState(1);
useEffect(() => { useEffect(() => {
if (!lockChat && inputRef.current) { if (!lockChat && inputRef.current) {
inputRef.current.focus(); inputRef.current.focus();
} }
}, [lockChat, inputRef]); }, [lockChat, inputRef]);
function handleChange(value: number) {
console.log(value);
if (value > 0) {
setRepeate(value);
} else {
setRepeate(1);
}
}
function handleChange(value:number){ useEffect(() => {
console.log(value) if (inputRef.current) {
if(value>0){ inputRef.current.style.height = "inherit"; // Reset the height
setRepeate(value); inputRef.current.style.height = `${inputRef.current.scrollHeight}px`; // Set it to the scrollHeight
} }
else{ }, [chatValue]);
setRepeate(1);
}
}
return (
<div className="relative">
<div className="flex flex-col">
<span className="text-xs">repeate</span>
<input
onChange={(e) => {
handleChange(parseInt(e.target.value));
}}
className="bg-background"
type="number"
min={0}
/>
</div>
<Textarea
onKeyDown={(event) => {
if (event.key === "Enter" && !lockChat && !event.shiftKey) {
sendMessage(repeate);
}
}}
rows={1}
ref={inputRef}
disabled={lockChat || noInput}
style={{
resize: "none",
bottom: `${inputRef?.current?.scrollHeight}px`,
maxHeight: "150px",
overflow: `${
inputRef.current && inputRef.current.scrollHeight > 150
? "auto"
: "hidden"
}`,
}}
value={lockChat ? "Thinking..." : chatValue}
onChange={(event): void => {
setChatValue(event.target.value);
}}
className={classNames(
lockChat
? " form-modal-lock-true bg-input"
: noInput
? "form-modal-no-input bg-input"
: " form-modal-lock-false bg-background",
useEffect(() => { "form-modal-lockchat"
if (inputRef.current) { )}
inputRef.current.style.height = "inherit"; // Reset the height placeholder={
inputRef.current.style.height = `${inputRef.current.scrollHeight}px`; // Set it to the scrollHeight noInput
} ? "No chat input variables found. Click to run your flow."
}, [chatValue]); : "Send a message..."
}
/>
return ( <div className="form-modal-send-icon-position">
<div className="relative"> <button
<div className="flex flex-col"> className={classNames(
<span className="text-xs">repeate</span> "form-modal-send-button",
<input onChange={(e)=>{ noInput
handleChange(parseInt(e.target.value)); ? "bg-high-indigo text-background"
}} className="bg-background" type="number" min={0}/> : chatValue === ""
? "text-primary"
: "bg-chat-send text-background"
</div> )}
<Textarea disabled={lockChat}
onKeyDown={(event) => { onClick={(): void => sendMessage()}
if (event.key === "Enter" && !lockChat && !event.shiftKey) { >
sendMessage(repeate); {lockChat ? (
} <IconComponent
}} name="Lock"
rows={1} className="form-modal-lock-icon"
ref={inputRef} aria-hidden="true"
disabled={lockChat || noInput} />
style={{ ) : noInput ? (
resize: "none", <IconComponent
bottom: `${inputRef?.current?.scrollHeight}px`, name="Sparkles"
maxHeight: "150px", className="form-modal-play-icon"
overflow: `${ aria-hidden="true"
inputRef.current && inputRef.current.scrollHeight > 150 />
? "auto" ) : (
: "hidden" <IconComponent
}`, name="LucideSend"
}} className="form-modal-send-icon "
value={lockChat ? "Thinking..." : chatValue} aria-hidden="true"
onChange={(event): void => { />
setChatValue(event.target.value); )}
}} </button>
className={classNames( </div>
lockChat </div>
? " form-modal-lock-true bg-input" );
: noInput
? "form-modal-no-input bg-input"
: " form-modal-lock-false bg-background",
"form-modal-lockchat"
)}
placeholder={
noInput
? "No chat input variables found. Click to run your flow."
: "Send a message..."
}
/>
<div className="form-modal-send-icon-position">
<button
className={classNames(
"form-modal-send-button",
noInput
? "bg-high-indigo text-background"
: chatValue === ""
? "text-primary"
: "bg-chat-send text-background"
)}
disabled={lockChat}
onClick={(): void => sendMessage()}
>
{lockChat ? (
<IconComponent
name="Lock"
className="form-modal-lock-icon"
aria-hidden="true"
/>
) : noInput ? (
<IconComponent
name="Sparkles"
className="form-modal-play-icon"
aria-hidden="true"
/>
) : (
<IconComponent
name="LucideSend"
className="form-modal-send-icon "
aria-hidden="true"
/>
)}
</button>
</div>
</div>
);
} }

View file

@ -6,74 +6,67 @@ import { programmingLanguages } from "../../../../constants/constants";
import { Props } from "../../../../types/components"; import { Props } from "../../../../types/components";
export function CodeBlock({ language, value }: Props): JSX.Element { export function CodeBlock({ language, value }: Props): JSX.Element {
const [isCopied, setIsCopied] = useState<Boolean>(false); const [isCopied, setIsCopied] = useState<Boolean>(false);
const copyToClipboard = (): void => {
if (!navigator.clipboard || !navigator.clipboard.writeText) {
return;
}
const copyToClipboard = (): void => { navigator.clipboard.writeText(value).then(() => {
if (!navigator.clipboard || !navigator.clipboard.writeText) { setIsCopied(true);
return;
}
setTimeout(() => {
setIsCopied(false);
}, 2000);
});
};
const downloadAsFile = (): void => {
const fileExtension = programmingLanguages[language] || ".file";
const suggestedFileName = `${"generated-code"}${fileExtension}`;
const fileName = window.prompt("enter file name", suggestedFileName);
navigator.clipboard.writeText(value).then(() => { if (!fileName) {
setIsCopied(true); // user pressed cancel on prompt
return;
}
const blob = new Blob([value], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.download = fileName;
link.href = url;
link.style.display = "none";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
};
return (
<div className="codeblock font-sans text-[16px]">
<div className="code-block-modal">
<span className="code-block-modal-span">{language}</span>
setTimeout(() => { <div className="flex items-center">
setIsCopied(false); <button className="code-block-modal-button" onClick={copyToClipboard}>
}, 2000); {isCopied ? <IconCheck size={18} /> : <IconClipboard size={18} />}
}); {isCopied ? "Copied!" : "Copy code"}
}; </button>
const downloadAsFile = (): void => { <button className="code-block-modal-button" onClick={downloadAsFile}>
const fileExtension = programmingLanguages[language] || ".file"; <IconDownload size={18} />
const suggestedFileName = `${"generated-code"}${fileExtension}`; </button>
const fileName = window.prompt("enter file name", suggestedFileName); </div>
</div>
<SyntaxHighlighter
if (!fileName) { className="overflow-auto"
// user pressed cancel on prompt language={language}
return; style={oneDark}
} customStyle={{ margin: 0 }}
>
{value}
const blob = new Blob([value], { type: "text/plain" }); </SyntaxHighlighter>
const url = URL.createObjectURL(blob); </div>
const link = document.createElement("a"); );
link.download = fileName;
link.href = url;
link.style.display = "none";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
};
return (
<div className="codeblock font-sans text-[16px]">
<div className="code-block-modal">
<span className="code-block-modal-span">{language}</span>
<div className="flex items-center">
<button className="code-block-modal-button" onClick={copyToClipboard}>
{isCopied ? <IconCheck size={18} /> : <IconClipboard size={18} />}
{isCopied ? "Copied!" : "Copy code"}
</button>
<button className="code-block-modal-button" onClick={downloadAsFile}>
<IconDownload size={18} />
</button>
</div>
</div>
<SyntaxHighlighter
className="overflow-auto"
language={language}
style={oneDark}
customStyle={{ margin: 0 }}
>
{value}
</SyntaxHighlighter>
</div>
);
} }
CodeBlock.displayName = "CodeBlock"; CodeBlock.displayName = "CodeBlock";

View file

@ -13,222 +13,217 @@ import { chatMessagePropsType } from "../../../types/components";
import { classNames } from "../../../utils/utils"; import { classNames } from "../../../utils/utils";
import FileCard from "../fileComponent"; import FileCard from "../fileComponent";
export default function ChatMessage({ export default function ChatMessage({
chat, chat,
lockChat, lockChat,
lastMessage, lastMessage,
}: chatMessagePropsType): JSX.Element { }: chatMessagePropsType): JSX.Element {
const convert = new Convert({ newline: true }); const convert = new Convert({ newline: true });
const [hidden, setHidden] = useState(true); const [hidden, setHidden] = useState(true);
const template = chat.template; const template = chat.template;
const [promptOpen, setPromptOpen] = useState(false); const [promptOpen, setPromptOpen] = useState(false);
return ( return (
<div <div
className={classNames("form-modal-chat-position", chat.isSend ? "" : " ")} className={classNames("form-modal-chat-position", chat.isSend ? "" : " ")}
> >
<div className={classNames("form-modal-chatbot-icon ")}> <div className={classNames("form-modal-chatbot-icon ")}>
{!chat.isSend ? ( {!chat.isSend ? (
<div className="form-modal-chat-image"> <div className="form-modal-chat-image">
<div className="form-modal-chat-bot-icon "> <div className="form-modal-chat-bot-icon ">
<img <img
src={Robot} src={Robot}
className="form-modal-chat-icon-img" className="form-modal-chat-icon-img"
alt="robot_image" alt="robot_image"
/> />
</div> </div>
<span className="text-xs truncate">{chat.sender_name}</span> <span className="truncate text-xs">{chat.sender_name}</span>
</div> </div>
) : ( ) : (
<div className="form-modal-chat-image"> <div className="form-modal-chat-image">
<div className="form-modal-chat-user-icon "> <div className="form-modal-chat-user-icon ">
<img <img
src={MaleTechnology} src={MaleTechnology}
className="form-modal-chat-icon-img" className="form-modal-chat-icon-img"
alt="male_technology" alt="male_technology"
/> />
</div> </div>
<span className="text-xs truncate">{chat.sender_name}</span> <span className="truncate text-xs">{chat.sender_name}</span>
</div> </div>
)} )}
</div> </div>
{!chat.isSend ? ( {!chat.isSend ? (
<div className="form-modal-chat-text-position"> <div className="form-modal-chat-text-position">
<div className="form-modal-chat-text"> <div className="form-modal-chat-text">
{hidden && chat.thought && chat.thought !== "" && ( {hidden && chat.thought && chat.thought !== "" && (
<div <div
onClick={(): void => setHidden((prev) => !prev)} onClick={(): void => setHidden((prev) => !prev)}
className="form-modal-chat-icon-div" className="form-modal-chat-icon-div"
> >
<IconComponent <IconComponent
name="MessageSquare" name="MessageSquare"
className="form-modal-chat-icon" className="form-modal-chat-icon"
/> />
</div> </div>
)} )}
{chat.thought && chat.thought !== "" && !hidden && ( {chat.thought && chat.thought !== "" && !hidden && (
<SanitizedHTMLWrapper <SanitizedHTMLWrapper
className=" form-modal-chat-thought" className=" form-modal-chat-thought"
content={convert.toHtml(chat.thought)} content={convert.toHtml(chat.thought)}
onClick={() => setHidden((prev) => !prev)} onClick={() => setHidden((prev) => !prev)}
/> />
)} )}
{chat.thought && chat.thought !== "" && !hidden && <br></br>} {chat.thought && chat.thought !== "" && !hidden && <br></br>}
<div className="w-full"> <div className="w-full">
<div className="w-full dark:text-white"> <div className="w-full dark:text-white">
<div className="w-full"> <div className="w-full">
{useMemo( {useMemo(
() => () =>
chat.message.toString() === "" && lockChat ? ( chat.message.toString() === "" && lockChat ? (
<IconComponent <IconComponent
name="MoreHorizontal" name="MoreHorizontal"
className="h-8 w-8 animate-pulse" className="h-8 w-8 animate-pulse"
/> />
) : ( ) : (
<ReactMarkdown <ReactMarkdown
remarkPlugins={[remarkGfm, remarkMath]} remarkPlugins={[remarkGfm, remarkMath]}
rehypePlugins={[rehypeMathjax]} rehypePlugins={[rehypeMathjax]}
className="markdown prose min-w-full text-primary word-break-break-word className="markdown prose min-w-full text-primary word-break-break-word
dark:prose-invert" dark:prose-invert"
components={{ components={{
pre({ node, ...props }) { pre({ node, ...props }) {
return <>{props.children}</>; return <>{props.children}</>;
}, },
code: ({ code: ({
node, node,
inline, inline,
className, className,
children, children,
...props ...props
}) => { }) => {
if (children.length) { if (children.length) {
if (children[0] === "▍") { if (children[0] === "▍") {
return ( return (
<span className="form-modal-markdown-span"> <span className="form-modal-markdown-span">
▍ ▍
</span> </span>
); );
} }
children[0] = (children[0] as string).replace(
"`▍`",
"▍"
);
}
children[0] = (children[0] as string).replace( const match = /language-(\w+)/.exec(
"`▍`", className || ""
"▍" );
);
}
return !inline ? (
<CodeTabsComponent
isMessage
tabs={[
{
name: (match && match[1]) || "",
mode: (match && match[1]) || "",
image:
"https://curl.se/logo/curl-symbol-transparent.png",
language: (match && match[1]) || "",
code: String(children).replace(/\n$/, ""),
},
]}
activeTab={"0"}
setActiveTab={() => {}}
/>
) : (
<code className={className} {...props}>
{children}
</code>
);
},
}}
>
{chat.message.toString()}
</ReactMarkdown>
),
[chat.message, chat.message.toString()]
)}
</div>
{chat.files && (
<div className="my-2 w-full">
{chat.files.map((file, index) => {
return (
<div key={index} className="my-2 w-full">
<FileCard
fileName={"Generated File"}
fileType={file.data_type}
content={file.data}
/>
</div>
);
})}
</div>
)}
</div>
</div>
</div>
</div>
) : (
<div>
{template ? (
<>
<button
className="form-modal-initial-prompt-btn"
onClick={() => {
setPromptOpen((old) => !old);
}}
>
Display Prompt
<IconComponent
name="ChevronDown"
className={
"h-3 w-3 transition-all " + (promptOpen ? "rotate-180" : "")
}
/>
</button>
<span className="prose text-primary word-break-break-word dark:prose-invert">
{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>
);
}
const match = /language-(\w+)/.exec( // Update last index
className || "" lastIndex = regex.lastIndex;
); }
// Push text after the last match
if (lastIndex !== line.length) {
return !inline ? ( parts.push(line.substring(lastIndex));
<CodeTabsComponent }
isMessage return <p>{parts}</p>;
tabs={[ })
{ : chat.message.toString()}
name: (match && match[1]) || "", </span>
mode: (match && match[1]) || "", </>
image: ) : (
"https://curl.se/logo/curl-symbol-transparent.png", <span>{chat.message.toString()}</span>
language: (match && match[1]) || "", )}
code: String(children).replace(/\n$/, ""), </div>
}, )}
]} </div>
activeTab={"0"} );
setActiveTab={() => {}}
/>
) : (
<code className={className} {...props}>
{children}
</code>
);
},
}}
>
{chat.message.toString()}
</ReactMarkdown>
),
[chat.message, chat.message.toString()]
)}
</div>
{chat.files && (
<div className="my-2 w-full">
{chat.files.map((file, index) => {
return (
<div key={index} className="my-2 w-full">
<FileCard
fileName={"Generated File"}
fileType={file.data_type}
content={file.data}
/>
</div>
);
})}
</div>
)}
</div>
</div>
</div>
</div>
) : (
<div>
{template ? (
<>
<button
className="form-modal-initial-prompt-btn"
onClick={() => {
setPromptOpen((old) => !old);
}}
>
Display Prompt
<IconComponent
name="ChevronDown"
className={
"h-3 w-3 transition-all " + (promptOpen ? "rotate-180" : "")
}
/>
</button>
<span className="prose text-primary word-break-break-word dark:prose-invert">
{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>;
})
: chat.message.toString()}
</span>
</>
) : (
<span>{chat.message.toString()}</span>
)}
</div>
)}
</div>
);
} }

View file

@ -4,84 +4,82 @@ import IconComponent from "../../../components/genericIconComponent";
import { fileCardPropsType } from "../../../types/components"; import { fileCardPropsType } from "../../../types/components";
export default function FileCard({ export default function FileCard({
fileName, fileName,
content, content,
fileType, fileType,
}: fileCardPropsType): JSX.Element { }: fileCardPropsType): JSX.Element {
const handleDownload = (): void => { const handleDownload = (): void => {
const byteArray = new Uint8Array(base64js.toByteArray(content)); const byteArray = new Uint8Array(base64js.toByteArray(content));
const blob = new Blob([byteArray], { type: "application/octet-stream" }); const blob = new Blob([byteArray], { type: "application/octet-stream" });
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
const link = document.createElement("a"); const link = document.createElement("a");
link.href = url; link.href = url;
link.download = fileName + ".png"; link.download = fileName + ".png";
document.body.appendChild(link); document.body.appendChild(link);
link.click(); link.click();
document.body.removeChild(link); document.body.removeChild(link);
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
}; };
const [isHovered, setIsHovered] = useState(false); const [isHovered, setIsHovered] = useState(false);
function handleMouseEnter(): void { function handleMouseEnter(): void {
setIsHovered(true); setIsHovered(true);
} }
function handleMouseLeave(): void { function handleMouseLeave(): void {
setIsHovered(false); setIsHovered(false);
} }
if (fileType === "image") {
return (
<div
className="relative h-1/4 w-1/4"
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<img
src={`data:image/png;base64,${content}`}
alt="generated image"
className="h-full w-full rounded-lg"
/>
{isHovered && (
<div className={`file-card-modal-image-div `}>
<button
className="file-card-modal-image-button "
onClick={handleDownload}
>
<IconComponent
name="DownloadCloud"
className="h-5 w-5 text-current hover:scale-110"
/>
</button>
</div>
)}
</div>
);
}
if (fileType === "image") { return (
return ( <button onClick={handleDownload} className="file-card-modal-button">
<div <div className="file-card-modal-div">
className="relative h-1/4 w-1/4" ooooooooooooooo{" "}
onMouseEnter={handleMouseEnter} {fileType === "image" ? (
onMouseLeave={handleMouseLeave} <img
> src={`data:image/png;base64,${content}`}
<img alt=""
src={`data:image/png;base64,${content}`} className="h-8 w-8"
alt="generated image" />
className="h-full w-full rounded-lg" ) : (
/> <IconComponent name="File" className="h-8 w-8" />
{isHovered && ( )}
<div className={`file-card-modal-image-div `}> <div className="file-card-modal-footer">
<button {" "}
className="file-card-modal-image-button " <div className="file-card-modal-name">{fileName}</div>
onClick={handleDownload} <div className="file-card-modal-type">{fileType}</div>
> </div>
<IconComponent <IconComponent
name="DownloadCloud" name="DownloadCloud"
className="h-5 w-5 text-current hover:scale-110" className="ml-auto h-6 w-6 text-current"
/> />
</button> </div>
</div> </button>
)} );
</div>
);
}
return (
<button onClick={handleDownload} className="file-card-modal-button">
<div className="file-card-modal-div">
ooooooooooooooo{" "}
{fileType === "image" ? (
<img
src={`data:image/png;base64,${content}`}
alt=""
className="h-8 w-8"
/>
) : (
<IconComponent name="File" className="h-8 w-8" />
)}
<div className="file-card-modal-footer">
{" "}
<div className="file-card-modal-name">{fileName}</div>
<div className="file-card-modal-type">{fileType}</div>
</div>
<IconComponent
name="DownloadCloud"
className="ml-auto h-6 w-6 text-current"
/>
</div>
</button>
);
} }

View file

@ -1,193 +1,187 @@
import { useContext, useEffect, useRef, useState } from "react"; import { cloneDeep } from "lodash";
import { useEffect, useRef, useState } from "react";
import IconComponent from "../../components/genericIconComponent";
import useAlertStore from "../../stores/alertStore";
import useFlowStore from "../../stores/flowStore";
import useFlowIOStore from "../../stores/flowsIOStore";
import { sendAllProps } from "../../types/api"; import { sendAllProps } from "../../types/api";
import { ChatMessageType } from "../../types/chat"; import {
ChatMessageType,
ChatOutputType,
FlowPoolObjectType,
} from "../../types/chat";
import { NodeType } from "../../types/flow"; import { NodeType } from "../../types/flow";
import { validateNodes } from "../../utils/reactflowUtils";
import { classNames } from "../../utils/utils"; import { classNames } from "../../utils/utils";
import ChatInput from "./chatInput"; import ChatInput from "./chatInput";
import ChatMessage from "./chatMessage"; import ChatMessage from "./chatMessage";
import { cloneDeep } from "lodash";
import IconComponent from "../../components/genericIconComponent";
import {
ChatOutputType,
FlowPoolObjectType,
} from "../../types/chat";
import { validateNodes } from "../../utils/reactflowUtils";
import useAlertStore from "../../stores/alertStore";
import useFlowIOStore from "../../stores/flowsIOStore";
import useFlowsManagerStore from "../../stores/flowsManagerStore";
import useFlowStore from "../../stores/flowStore";
export default function newChatView(): JSX.Element { export default function newChatView(): JSX.Element {
const [chatValue, setChatValue] = useState(""); const [chatValue, setChatValue] = useState("");
const [chatHistory, setChatHistory] = useState<ChatMessageType[]>([]); const [chatHistory, setChatHistory] = useState<ChatMessageType[]>([]);
const { reactFlowInstance } = useFlowStore() const { reactFlowInstance } = useFlowStore();
const { const {
flowPool, flowPool,
outputIds, outputIds,
inputIds, inputTypes, inputIds,
updateNodeFlowData, inputTypes,
buildFlow, updateNodeFlowData,
CleanFlowPool buildFlow,
} = useFlowIOStore(); CleanFlowPool,
const { setErrorData } = useAlertStore(); } = useFlowIOStore();
const [lockChat, setLockChat] = useState(false); const { setErrorData } = useAlertStore();
const messagesRef = useRef<HTMLDivElement | null>(null); const [lockChat, setLockChat] = useState(false);
const messagesRef = useRef<HTMLDivElement | null>(null);
//build chat history
useEffect(() => {
const chatOutputResponses: FlowPoolObjectType[] = [];
outputIds.forEach((outputId) => {
if (outputId.includes("ChatOutput")) {
if (flowPool[outputId] && flowPool[outputId].length > 0) {
chatOutputResponses.push(...flowPool[outputId]);
}
}
});
const chatMessages: ChatMessageType[] = chatOutputResponses
.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp))
.filter((output) => !!output.data.artifacts.message)
.map((output) => {
const { sender, message, sender_name } = output.data
.artifacts as ChatOutputType;
console.log(output.data.artifacts);
const is_ai = sender === "Machine";
return { isSend: !is_ai, message, sender_name };
});
setChatHistory(chatMessages);
}, [flowPool, outputIds]);
useEffect(() => {
if (messagesRef.current) {
messagesRef.current.scrollTop = messagesRef.current.scrollHeight;
}
}, [chatHistory]);
//build chat history async function sendAll(data: sendAllProps): Promise<void> {}
useEffect(() => { useEffect(() => {
const chatOutputResponses: FlowPoolObjectType[] = []; if (ref.current) ref.current.scrollIntoView({ behavior: "smooth" });
outputIds.forEach((outputId) => { }, [chatHistory]);
if (outputId.includes("ChatOutput")) {
if (flowPool[outputId] && flowPool[outputId].length > 0) {
chatOutputResponses.push(...flowPool[outputId]);
}
}
});
const chatMessages: ChatMessageType[] = chatOutputResponses
.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp)).filter((output) => !!output.data.artifacts.message)
.map((output) => {
const { sender, message, sender_name } = output.data.artifacts as ChatOutputType;
console.log(output.data.artifacts);
const is_ai = sender === "Machine";
return { isSend: !is_ai, message, sender_name };
});
setChatHistory(chatMessages);
}, [flowPool, outputIds]);
useEffect(() => {
if (messagesRef.current) {
messagesRef.current.scrollTop = messagesRef.current.scrollHeight;
}
}, [chatHistory]);
const ref = useRef<HTMLDivElement | null>(null);
async function sendAll(data: sendAllProps): Promise<void> { } useEffect(() => {
useEffect(() => { if (ref.current) {
if (ref.current) ref.current.scrollIntoView({ behavior: "smooth" }); ref.current.focus();
}, [chatHistory]); }
}, []);
async function sendMessage(count = 1): Promise<void> {
let nodeValidationErrors = validateNodes(
reactFlowInstance!.getNodes(),
reactFlowInstance!.getEdges()
);
if (nodeValidationErrors.length === 0) {
setLockChat(true);
setChatValue("");
const chatInputId = inputIds.find((inputId) =>
inputId.includes("ChatInput")
);
const chatInput: NodeType = reactFlowInstance?.getNode(
chatInputId!
) as NodeType;
if (chatInput) {
let newData = cloneDeep(chatInput.data);
newData.node!.template["message"].value = chatValue;
chatInput.data = { ...newData };
updateNodeFlowData(chatInputId!, newData);
}
for (let i = 0; i < count; i++) {
await buildFlow().catch((err) => {
console.error(err);
setLockChat(false);
});
}
setLockChat(false);
const ref = useRef<HTMLDivElement | null>(null); //set chat message in the flow and run build
//@ts-ignore
} else {
setErrorData({
title: "Oops! Looks like you missed some required information:",
list: nodeValidationErrors,
});
}
}
function clearChat(): void {
setChatHistory([]);
CleanFlowPool();
//TODO tell backend to clear chat session
if (lockChat) setLockChat(false);
}
return (
useEffect(() => { <div className="eraser-column-arrangement">
if (ref.current) { <div className="eraser-size">
ref.current.focus(); <div className="eraser-position">
} <button disabled={lockChat} onClick={() => clearChat()}>
}, []); <IconComponent
name="Eraser"
className={classNames(
async function sendMessage(count = 1): Promise<void> { "h-5 w-5",
let nodeValidationErrors = validateNodes( lockChat
reactFlowInstance!.getNodes(), ? "animate-pulse text-primary"
reactFlowInstance!.getEdges() : "text-primary hover:text-gray-600"
); )}
if (nodeValidationErrors.length === 0) { aria-hidden="true"
setLockChat(true); />
setChatValue(""); </button>
const chatInputId = inputIds.find((inputId) => </div>
inputId.includes("ChatInput") <div ref={messagesRef} className="chat-message-div">
); {chatHistory?.length > 0 ? (
const chatInput: NodeType = reactFlowInstance?.getNode( chatHistory.map((chat, index) => (
chatInputId! <ChatMessage
) as NodeType; lockChat={lockChat}
if (chatInput) { chat={chat}
let newData = cloneDeep(chatInput.data); lastMessage={chatHistory.length - 1 === index ? true : false}
newData.node!.template["message"].value = chatValue; key={index}
chatInput.data = { ...newData }; />
updateNodeFlowData(chatInputId!, newData); ))
} ) : (
for (let i = 0; i < count; i++) { <div className="chat-alert-box">
await buildFlow().catch((err) => { <span>
console.error(err); 👋 <span className="langflow-chat-span">Langflow Chat</span>
setLockChat(false); </span>
}); <br />
} <div className="langflow-chat-desc">
setLockChat(false); <span className="langflow-chat-desc-span">
Start a conversation and click the agent's thoughts{" "}
<span>
//set chat message in the flow and run build <IconComponent
//@ts-ignore name="MessageSquare"
} else { className="mx-1 inline h-5 w-5 animate-bounce "
setErrorData({ />
title: "Oops! Looks like you missed some required information:", </span>{" "}
list: nodeValidationErrors, to inspect the chaining process.
}); </span>
} </div>
} </div>
function clearChat(): void { )}
setChatHistory([]); <div ref={ref}></div>
CleanFlowPool(); </div>
//TODO tell backend to clear chat session <div className="langflow-chat-input-div">
if (lockChat) setLockChat(false); <div className="langflow-chat-input">
} <ChatInput
chatValue={chatValue}
noInput={!inputTypes.includes("ChatInput")}
return ( lockChat={lockChat}
<div className="eraser-column-arrangement"> sendMessage={(count) => sendMessage(count)}
<div className="eraser-size"> setChatValue={(value) => {
<div className="eraser-position"> setChatValue(value);
<button disabled={lockChat} onClick={() => clearChat()}> }}
<IconComponent inputRef={ref}
name="Eraser" />
className={classNames( </div>
"h-5 w-5", </div>
lockChat </div>
? "animate-pulse text-primary" </div>
: "text-primary hover:text-gray-600" );
)}
aria-hidden="true"
/>
</button>
</div>
<div ref={messagesRef} className="chat-message-div">
{chatHistory?.length > 0 ? (
chatHistory.map((chat, index) => (
<ChatMessage
lockChat={lockChat}
chat={chat}
lastMessage={chatHistory.length - 1 === index ? true : false}
key={index}
/>
))
) : (
<div className="chat-alert-box">
<span>
👋 <span className="langflow-chat-span">Langflow Chat</span>
</span>
<br />
<div className="langflow-chat-desc">
<span className="langflow-chat-desc-span">
Start a conversation and click the agent's thoughts{" "}
<span>
<IconComponent
name="MessageSquare"
className="mx-1 inline h-5 w-5 animate-bounce "
/>
</span>{" "}
to inspect the chaining process.
</span>
</div>
</div>
)}
<div ref={ref}></div>
</div>
<div className="langflow-chat-input-div">
<div className="langflow-chat-input">
<ChatInput
chatValue={chatValue}
noInput={!inputTypes.includes("ChatInput")}
lockChat={lockChat}
sendMessage={(count) => sendMessage(count)}
setChatValue={(value) => {
setChatValue(value);
}}
inputRef={ref}
/>
</div>
</div>
</div>
</div>
);
} }

View file

@ -1,15 +1,15 @@
export default function TextInputComponent({ export default function TextInputComponent({
text, text,
emissor, emissor,
}: { }: {
text: string; text: string;
emissor: string; emissor: string;
}) { }) {
return ( return (
<div> <div>
<strong> {emissor}</strong> <strong> {emissor}</strong>
<br></br> <br></br>
<span>{text}</span> <span>{text}</span>
</div> </div>
); );
} }

View file

@ -1,15 +1,15 @@
export default function TextOutputComponent({ export default function TextOutputComponent({
text, text,
emissor, emissor,
}: { }: {
text: string; text: string;
emissor: string; emissor: string;
}) { }) {
return ( return (
<div> <div>
<strong>{emissor}</strong> <strong>{emissor}</strong>
<br></br> <br></br>
<div className="w-80 break-all">{text}</div> <div className="w-80 break-all">{text}</div>
</div> </div>
); );
} }

View file

@ -678,5 +678,5 @@ export const LANGFLOW_SUPPORTED_TYPES = new Set([
export const priorityFields = new Set(["code", "template"]); export const priorityFields = new Set(["code", "template"]);
export const INPUT_TYPES = new Set(["ChatInput","TextInput"]); export const INPUT_TYPES = new Set(["ChatInput", "TextInput"]);
export const OUTPUT_TYPES = new Set(["ChatOutput"]); export const OUTPUT_TYPES = new Set(["ChatOutput"]);

View file

@ -9,7 +9,6 @@ import ReactFlow, {
OnMove, OnMove,
OnSelectionChangeParams, OnSelectionChangeParams,
SelectionDragHandler, SelectionDragHandler,
addEdge,
updateEdge, updateEdge,
} from "reactflow"; } from "reactflow";
import GenericNode from "../../../../CustomNodes/GenericNode"; import GenericNode from "../../../../CustomNodes/GenericNode";
@ -19,13 +18,12 @@ import useFlowStore from "../../../../stores/flowStore";
import useFlowsManagerStore from "../../../../stores/flowsManagerStore"; import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
import { useTypesStore } from "../../../../stores/typesStore"; import { useTypesStore } from "../../../../stores/typesStore";
import { APIClassType } from "../../../../types/api"; import { APIClassType } from "../../../../types/api";
import { FlowType, NodeType, targetHandleType } from "../../../../types/flow"; import { FlowType, NodeType } from "../../../../types/flow";
import { import {
generateFlow, generateFlow,
generateNodeFromFlow, generateNodeFromFlow,
getNodeId, getNodeId,
isValidConnection, isValidConnection,
scapeJSONParse,
validateSelection, validateSelection,
} from "../../../../utils/reactflowUtils"; } from "../../../../utils/reactflowUtils";
import { getRandomName, isWrappedWithClass } from "../../../../utils/utils"; import { getRandomName, isWrappedWithClass } from "../../../../utils/utils";
@ -175,8 +173,8 @@ export default function Page({
useEffect(() => { useEffect(() => {
return () => { return () => {
cleanFlow(); cleanFlow();
} };
}, []) }, []);
const onConnectMod = useCallback( const onConnectMod = useCallback(
(params: Connection) => { (params: Connection) => {
@ -332,7 +330,7 @@ export default function Page({
<div className="h-full w-full"> <div className="h-full w-full">
<div className="h-full w-full" ref={reactFlowWrapper}> <div className="h-full w-full" ref={reactFlowWrapper}>
{Object.keys(templates).length > 0 && {Object.keys(templates).length > 0 &&
Object.keys(types).length > 0 ? ( Object.keys(types).length > 0 ? (
<div id="react-flow-id" className="h-full w-full"> <div id="react-flow-id" className="h-full w-full">
<ReactFlow <ReactFlow
nodes={nodes} nodes={nodes}

View file

@ -4,7 +4,7 @@ import {
Select, Select,
SelectContent, SelectContent,
SelectItem, SelectItem,
SelectTrigger SelectTrigger,
} from "../../../../../components/ui/select-custom"; } from "../../../../../components/ui/select-custom";
import { useDarkStore } from "../../../../../stores/darkStore"; import { useDarkStore } from "../../../../../stores/darkStore";
import useFlowsManagerStore from "../../../../../stores/flowsManagerStore"; import useFlowsManagerStore from "../../../../../stores/flowsManagerStore";

View file

@ -265,7 +265,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
}, },
getFilterEdge: [], getFilterEdge: [],
onConnect: (connection) => { onConnect: (connection) => {
let newEdges: Edge[] = [] let newEdges: Edge[] = [];
get().setEdges((oldEdges) => { get().setEdges((oldEdges) => {
newEdges = addEdge( newEdges = addEdge(
{ {
@ -287,8 +287,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
oldEdges oldEdges
); );
return newEdges; return newEdges;
});
})
useFlowsManagerStore useFlowsManagerStore
.getState() .getState()
.autoSaveCurrentFlow( .autoSaveCurrentFlow(

View file

@ -19,7 +19,6 @@ const useFlowIOStore = create<flowIOStoreType>((set, get) => ({
inputTypes: [], inputTypes: [],
inputIds: [], inputIds: [],
outputIds: [], outputIds: [],
setFlowPool: (flowPool) => { setFlowPool: (flowPool) => {
set({ flowPool }); set({ flowPool });
}, },

View file

@ -43,5 +43,4 @@ export const useTypesStore = create<TypesStoreType>((set, get) => ({
let newChange = typeof change === "function" ? change(get().data) : change; let newChange = typeof change === "function" ? change(get().data) : change;
set({ data: newChange }); set({ data: newChange });
}, },
})); }));

View file

@ -444,7 +444,7 @@ export type chatInputType = {
}; };
lockChat: boolean; lockChat: boolean;
noInput: boolean; noInput: boolean;
sendMessage: (count?:number) => void; sendMessage: (count?: number) => void;
setChatValue: (value: string) => void; setChatValue: (value: string) => void;
}; };

View file

@ -1,81 +1,85 @@
import { AxiosError } from "axios"; import { AxiosError } from "axios";
import { FlowType } from "../types/flow";
import { getVerticesOrder, postBuildVertex } from "../controllers/API"; import { getVerticesOrder, postBuildVertex } from "../controllers/API";
import { FlowType } from "../types/flow";
type BuildVerticesParams = { type BuildVerticesParams = {
flow: FlowType; // Assuming FlowType is the type for your flow flow: FlowType; // Assuming FlowType is the type for your flow
nodeId?: string | null; // Assuming nodeId is of type string, and it's optional nodeId?: string | null; // Assuming nodeId is of type string, and it's optional
onProgressUpdate?: (progress: number) => void; // Replace number with the actual type if it's not a number onProgressUpdate?: (progress: number) => void; // Replace number with the actual type if it's not a number
onBuildUpdate?: (data: any) => void; // Replace any with the actual type of data onBuildUpdate?: (data: any) => void; // Replace any with the actual type of data
onBuildComplete?: (allNodesValid: boolean) => void; onBuildComplete?: (allNodesValid: boolean) => void;
onBuildError?: (title, list) => void; onBuildError?: (title, list) => void;
}; };
export async function buildVertices({ export async function buildVertices({
flow, flow,
nodeId = null, nodeId = null,
onProgressUpdate, onProgressUpdate,
onBuildUpdate, onBuildUpdate,
onBuildComplete, onBuildComplete,
onBuildError, onBuildError,
}: BuildVerticesParams) { }: BuildVerticesParams) {
try { try {
// Step 1: Get vertices order // Step 1: Get vertices order
console.log(JSON.parse(JSON.stringify(flow))); console.log(JSON.parse(JSON.stringify(flow)));
let orderResponse = await getVerticesOrder(flow.id); let orderResponse = await getVerticesOrder(flow.id);
let verticesOrder = orderResponse.data.ids.flatMap((id) => id); let verticesOrder = orderResponse.data.ids.flatMap((id) => id);
// Determine the range of vertices to build // Determine the range of vertices to build
let vertexIndex: number | null = null; let vertexIndex: number | null = null;
if (nodeId) { if (nodeId) {
vertexIndex = verticesOrder.indexOf(nodeId); vertexIndex = verticesOrder.indexOf(nodeId);
} }
let buildRange = let buildRange =
vertexIndex !== null vertexIndex !== null
? verticesOrder.slice(0, vertexIndex + 1) ? verticesOrder.slice(0, vertexIndex + 1)
: verticesOrder; : verticesOrder;
const buildResults: boolean[] = []; const buildResults: boolean[] = [];
for (let vertexId of buildRange) { for (let vertexId of buildRange) {
try { try {
const buildResponse = await postBuildVertex(flow, vertexId); const buildResponse = await postBuildVertex(flow, vertexId);
const buildData = buildResponse.data; const buildData = buildResponse.data;
if (onProgressUpdate) { if (onProgressUpdate) {
const progress = const progress =
verticesOrder.indexOf(vertexId) / verticesOrder.length; verticesOrder.indexOf(vertexId) / verticesOrder.length;
onProgressUpdate(progress); onProgressUpdate(progress);
}
if (onBuildUpdate) {
let data = {};
if (!buildData.valid) {
if (onBuildError) {
onBuildError("Error Building Component", [buildData.params]);
}
}
data[buildData.id] = buildData;
onBuildUpdate({ data, id: buildData.id });
}
buildResults.push(buildData.valid);
} catch (error : any) {
if (onBuildError) {
console.log(error)
onBuildError("Error Building Component", [(error as AxiosError<any>).response?.data?.detail??"Unknown Error"]);
}
} }
} if (onBuildUpdate) {
let data = {};
// Callback for when all vertices have been built if (!buildData.valid) {
if (onBuildComplete) { if (onBuildError) {
const allNodesValid = buildResults.every((result) => result); onBuildError("Error Building Component", [buildData.params]);
onBuildComplete(allNodesValid); }
} }
} catch (error:any) { data[buildData.id] = buildData;
// Callback for handling errors
if (onBuildError) { onBuildUpdate({ data, id: buildData.id });
}
buildResults.push(buildData.valid);
} catch (error: any) {
if (onBuildError) { if (onBuildError) {
onBuildError("Error Building Component", [(error as AxiosError<any>).response?.data?.detail??"Unknown Error"]); console.log(error);
onBuildError("Error Building Component", [
(error as AxiosError<any>).response?.data?.detail ??
"Unknown Error",
]);
} }
} }
} }
}
// Callback for when all vertices have been built
if (onBuildComplete) {
const allNodesValid = buildResults.every((result) => result);
onBuildComplete(allNodesValid);
}
} catch (error: any) {
// Callback for handling errors
if (onBuildError) {
if (onBuildError) {
onBuildError("Error Building Component", [
(error as AxiosError<any>).response?.data?.detail ?? "Unknown Error",
]);
}
}
}
}

View file

@ -477,7 +477,7 @@ export function convertArrayToObj(arrayOfObjects) {
export function hasDuplicateKeys(array) { export function hasDuplicateKeys(array) {
const keys = {}; const keys = {};
// Transforms an empty object into an object array without opening the 'editNode' modal to prevent the flow build from breaking. // Transforms an empty object into an object array without opening the 'editNode' modal to prevent the flow build from breaking.
if (!Array.isArray(array)) array = [{"": ""}]; if (!Array.isArray(array)) array = [{ "": "" }];
for (const obj of array) { for (const obj of array) {
for (const key in obj) { for (const key in obj) {
if (keys[key]) { if (keys[key]) {

View file

@ -593,7 +593,7 @@ export function removeCountFromString(input: string): string {
} }
export function extractTypeFromLongId(id: string): string { export function extractTypeFromLongId(id: string): string {
let [newId,_] = id.split("-"); let [newId, _] = id.split("-");
return newId; return newId;
} }