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):
"""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.
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.
@ -81,7 +83,9 @@ class MidJourneyPromptChain(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:
{history}
Human: {input}

View file

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

View file

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

View file

@ -1,93 +1,92 @@
import { ReactNode, useContext, 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 { ReactNode, useState } from "react";
import useFlowStore from "../../stores/flowStore";
import useFlowsManagerStore from "../../stores/flowsManagerStore";
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 {
const {inputIds, outputIds, updateNodeFlowData } =
useFlowIOStore();
const { reactFlowInstance } = useFlowStore();
const options = inputIds.concat(outputIds);
const [selectedView, setSelectedView] = useState<ReactNode>(handleSelectChange(options[0]));
// if (outputTypes.includes("ChatOutput")) {
// return <NewChatView />;
// }
function handleSelectChange(selected: string) {
const type = extractTypeFromLongId(selected);
return <NewChatView />
switch (type) {
case "ChatOutput":
return <NewChatView />;
break;
}
}
const { inputIds, outputIds, updateNodeFlowData } = useFlowIOStore();
const { reactFlowInstance } = useFlowStore();
const options = inputIds.concat(outputIds);
const [selectedView, setSelectedView] = useState<ReactNode>(
handleSelectChange(options[0])
);
// if (outputTypes.includes("ChatOutput")) {
// return <NewChatView />;
// }
function handleSelectChange(selected: string) {
const type = extractTypeFromLongId(selected);
return <NewChatView />;
switch (type) {
case "ChatOutput":
return <NewChatView />;
break;
}
}
return (
<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="file-component-arrangement">
<IconComponent
name="Variable"
className=" file-component-variable"
/>
<span className="file-component-variables-span text-md">
Inputs
</span>
</div>
{
inputIds.filter(input=>extractTypeFromLongId(input)!=="ChatInput").map((inputId,index) => {
const nodeData:NodeDataType = reactFlowInstance?.getNodes().find(node=>node.id===inputId)?.data;
return (
<div className="file-component-accordion-div" key={index}>
<AccordionComponent
trigger={
<div className="file-component-badge-div">
<Badge variant="gray" size="md">
{inputId}
</Badge>
<div
className="-mb-1"
onClick={(event) => {
event.stopPropagation();
}}
>
</div>
</div>
}
key={index}
keyValue={inputId}
>
<div className="file-component-tab-column">
<Textarea
value={reactFlowInstance?.getNodes().find(node=>node.id===inputId)?.data?.node?.template?.value.value}
className="custom-scroll"
onChange={(e) => {
e.target.value;
if(nodeData){
nodeData.node!.template["value"].value = e.target.value;
updateNodeFlowData(inputId,nodeData);
}
}}
placeholder="Enter text..."
></Textarea>
</div>
</AccordionComponent>
</div>
)
})
}
</div>
{selectedView}
</div>
);
return (
<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="file-component-arrangement">
<IconComponent name="Variable" className=" file-component-variable" />
<span className="file-component-variables-span text-md">Inputs</span>
</div>
{inputIds
.filter((input) => extractTypeFromLongId(input) !== "ChatInput")
.map((inputId, index) => {
const nodeData: NodeDataType = reactFlowInstance
?.getNodes()
.find((node) => node.id === inputId)?.data;
return (
<div className="file-component-accordion-div" key={index}>
<AccordionComponent
trigger={
<div className="file-component-badge-div">
<Badge variant="gray" size="md">
{inputId}
</Badge>
<div
className="-mb-1"
onClick={(event) => {
event.stopPropagation();
}}
></div>
</div>
}
key={index}
keyValue={inputId}
>
<div className="file-component-tab-column">
<Textarea
value={
reactFlowInstance
?.getNodes()
.find((node) => node.id === inputId)?.data?.node
?.template?.value.value
}
className="custom-scroll"
onChange={(e) => {
e.target.value;
if (nodeData) {
nodeData.node!.template["value"].value =
e.target.value;
updateNodeFlowData(inputId, nodeData);
}
}}
placeholder="Enter text..."
></Textarea>
</div>
</AccordionComponent>
</div>
);
})}
</div>
{selectedView}
</div>
);
}

View file

@ -5,123 +5,121 @@ import { chatInputType } from "../../../types/components";
import { classNames } from "../../../utils/utils";
export default function ChatInput({
lockChat,
chatValue,
sendMessage,
setChatValue,
inputRef,
noInput,
lockChat,
chatValue,
sendMessage,
setChatValue,
inputRef,
noInput,
}: chatInputType): JSX.Element {
const [repeate, setRepeate] = useState(1);
useEffect(() => {
if (!lockChat && inputRef.current) {
inputRef.current.focus();
}
}, [lockChat, inputRef]);
const [repeate, setRepeate] = useState(1);
useEffect(() => {
if (!lockChat && inputRef.current) {
inputRef.current.focus();
}
}, [lockChat, inputRef]);
function handleChange(value: number) {
console.log(value);
if (value > 0) {
setRepeate(value);
} else {
setRepeate(1);
}
}
function handleChange(value:number){
console.log(value)
if(value>0){
setRepeate(value);
}
else{
setRepeate(1);
}
}
useEffect(() => {
if (inputRef.current) {
inputRef.current.style.height = "inherit"; // Reset the height
inputRef.current.style.height = `${inputRef.current.scrollHeight}px`; // Set it to the scrollHeight
}
}, [chatValue]);
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(() => {
if (inputRef.current) {
inputRef.current.style.height = "inherit"; // Reset the height
inputRef.current.style.height = `${inputRef.current.scrollHeight}px`; // Set it to the scrollHeight
}
}, [chatValue]);
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",
"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>
);
"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";
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 => {
if (!navigator.clipboard || !navigator.clipboard.writeText) {
return;
}
navigator.clipboard.writeText(value).then(() => {
setIsCopied(true);
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(() => {
setIsCopied(true);
if (!fileName) {
// 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(() => {
setIsCopied(false);
}, 2000);
});
};
const downloadAsFile = (): void => {
const fileExtension = programmingLanguages[language] || ".file";
const suggestedFileName = `${"generated-code"}${fileExtension}`;
const fileName = window.prompt("enter file name", suggestedFileName);
<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>
if (!fileName) {
// 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>
<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>
);
<SyntaxHighlighter
className="overflow-auto"
language={language}
style={oneDark}
customStyle={{ margin: 0 }}
>
{value}
</SyntaxHighlighter>
</div>
);
}
CodeBlock.displayName = "CodeBlock";

View file

@ -13,222 +13,217 @@ import { chatMessagePropsType } from "../../../types/components";
import { classNames } from "../../../utils/utils";
import FileCard from "../fileComponent";
export default function ChatMessage({
chat,
lockChat,
lastMessage,
chat,
lockChat,
lastMessage,
}: chatMessagePropsType): JSX.Element {
const convert = new Convert({ newline: true });
const [hidden, setHidden] = useState(true);
const template = chat.template;
const [promptOpen, setPromptOpen] = useState(false);
return (
<div
className={classNames("form-modal-chat-position", chat.isSend ? "" : " ")}
>
<div className={classNames("form-modal-chatbot-icon ")}>
{!chat.isSend ? (
<div className="form-modal-chat-image">
<div className="form-modal-chat-bot-icon ">
<img
src={Robot}
className="form-modal-chat-icon-img"
alt="robot_image"
/>
</div>
<span className="text-xs truncate">{chat.sender_name}</span>
</div>
) : (
<div className="form-modal-chat-image">
<div className="form-modal-chat-user-icon ">
<img
src={MaleTechnology}
className="form-modal-chat-icon-img"
alt="male_technology"
/>
</div>
<span className="text-xs truncate">{chat.sender_name}</span>
</div>
)}
</div>
{!chat.isSend ? (
<div className="form-modal-chat-text-position">
<div className="form-modal-chat-text">
{hidden && chat.thought && chat.thought !== "" && (
<div
onClick={(): void => setHidden((prev) => !prev)}
className="form-modal-chat-icon-div"
>
<IconComponent
name="MessageSquare"
className="form-modal-chat-icon"
/>
</div>
)}
{chat.thought && chat.thought !== "" && !hidden && (
<SanitizedHTMLWrapper
className=" form-modal-chat-thought"
content={convert.toHtml(chat.thought)}
onClick={() => setHidden((prev) => !prev)}
/>
)}
{chat.thought && chat.thought !== "" && !hidden && <br></br>}
<div className="w-full">
<div className="w-full dark:text-white">
<div className="w-full">
{useMemo(
() =>
chat.message.toString() === "" && lockChat ? (
<IconComponent
name="MoreHorizontal"
className="h-8 w-8 animate-pulse"
/>
) : (
<ReactMarkdown
remarkPlugins={[remarkGfm, remarkMath]}
rehypePlugins={[rehypeMathjax]}
className="markdown prose min-w-full text-primary word-break-break-word
const convert = new Convert({ newline: true });
const [hidden, setHidden] = useState(true);
const template = chat.template;
const [promptOpen, setPromptOpen] = useState(false);
return (
<div
className={classNames("form-modal-chat-position", chat.isSend ? "" : " ")}
>
<div className={classNames("form-modal-chatbot-icon ")}>
{!chat.isSend ? (
<div className="form-modal-chat-image">
<div className="form-modal-chat-bot-icon ">
<img
src={Robot}
className="form-modal-chat-icon-img"
alt="robot_image"
/>
</div>
<span className="truncate text-xs">{chat.sender_name}</span>
</div>
) : (
<div className="form-modal-chat-image">
<div className="form-modal-chat-user-icon ">
<img
src={MaleTechnology}
className="form-modal-chat-icon-img"
alt="male_technology"
/>
</div>
<span className="truncate text-xs">{chat.sender_name}</span>
</div>
)}
</div>
{!chat.isSend ? (
<div className="form-modal-chat-text-position">
<div className="form-modal-chat-text">
{hidden && chat.thought && chat.thought !== "" && (
<div
onClick={(): void => setHidden((prev) => !prev)}
className="form-modal-chat-icon-div"
>
<IconComponent
name="MessageSquare"
className="form-modal-chat-icon"
/>
</div>
)}
{chat.thought && chat.thought !== "" && !hidden && (
<SanitizedHTMLWrapper
className=" form-modal-chat-thought"
content={convert.toHtml(chat.thought)}
onClick={() => setHidden((prev) => !prev)}
/>
)}
{chat.thought && chat.thought !== "" && !hidden && <br></br>}
<div className="w-full">
<div className="w-full dark:text-white">
<div className="w-full">
{useMemo(
() =>
chat.message.toString() === "" && lockChat ? (
<IconComponent
name="MoreHorizontal"
className="h-8 w-8 animate-pulse"
/>
) : (
<ReactMarkdown
remarkPlugins={[remarkGfm, remarkMath]}
rehypePlugins={[rehypeMathjax]}
className="markdown prose min-w-full text-primary word-break-break-word
dark:prose-invert"
components={{
pre({ node, ...props }) {
return <>{props.children}</>;
},
code: ({
node,
inline,
className,
children,
...props
}) => {
if (children.length) {
if (children[0] === "▍") {
return (
<span className="form-modal-markdown-span">
</span>
);
}
components={{
pre({ node, ...props }) {
return <>{props.children}</>;
},
code: ({
node,
inline,
className,
children,
...props
}) => {
if (children.length) {
if (children[0] === "▍") {
return (
<span className="form-modal-markdown-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(
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>
);
}
// 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>
);
// 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";
export default function FileCard({
fileName,
content,
fileType,
fileName,
content,
fileType,
}: fileCardPropsType): JSX.Element {
const handleDownload = (): void => {
const byteArray = new Uint8Array(base64js.toByteArray(content));
const blob = new Blob([byteArray], { type: "application/octet-stream" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = fileName + ".png";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
};
const [isHovered, setIsHovered] = useState(false);
function handleMouseEnter(): void {
setIsHovered(true);
}
function handleMouseLeave(): void {
setIsHovered(false);
}
const handleDownload = (): void => {
const byteArray = new Uint8Array(base64js.toByteArray(content));
const blob = new Blob([byteArray], { type: "application/octet-stream" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = fileName + ".png";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
};
const [isHovered, setIsHovered] = useState(false);
function handleMouseEnter(): void {
setIsHovered(true);
}
function handleMouseLeave(): void {
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 (
<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>
);
}
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>
);
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 { ChatMessageType } from "../../types/chat";
import {
ChatMessageType,
ChatOutputType,
FlowPoolObjectType,
} from "../../types/chat";
import { NodeType } from "../../types/flow";
import { validateNodes } from "../../utils/reactflowUtils";
import { classNames } from "../../utils/utils";
import ChatInput from "./chatInput";
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 {
const [chatValue, setChatValue] = useState("");
const [chatHistory, setChatHistory] = useState<ChatMessageType[]>([]);
const { reactFlowInstance } = useFlowStore()
const {
flowPool,
outputIds,
inputIds, inputTypes,
updateNodeFlowData,
buildFlow,
CleanFlowPool
} = useFlowIOStore();
const { setErrorData } = useAlertStore();
const [lockChat, setLockChat] = useState(false);
const messagesRef = useRef<HTMLDivElement | null>(null);
const [chatValue, setChatValue] = useState("");
const [chatHistory, setChatHistory] = useState<ChatMessageType[]>([]);
const { reactFlowInstance } = useFlowStore();
const {
flowPool,
outputIds,
inputIds,
inputTypes,
updateNodeFlowData,
buildFlow,
CleanFlowPool,
} = useFlowIOStore();
const { setErrorData } = useAlertStore();
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
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]);
async function sendAll(data: sendAllProps): Promise<void> {}
useEffect(() => {
if (ref.current) ref.current.scrollIntoView({ behavior: "smooth" });
}, [chatHistory]);
const ref = useRef<HTMLDivElement | null>(null);
async function sendAll(data: sendAllProps): Promise<void> { }
useEffect(() => {
if (ref.current) ref.current.scrollIntoView({ behavior: "smooth" });
}, [chatHistory]);
useEffect(() => {
if (ref.current) {
ref.current.focus();
}
}, []);
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);
}
useEffect(() => {
if (ref.current) {
ref.current.focus();
}
}, []);
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);
//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 (
<div className="eraser-column-arrangement">
<div className="eraser-size">
<div className="eraser-position">
<button disabled={lockChat} onClick={() => clearChat()}>
<IconComponent
name="Eraser"
className={classNames(
"h-5 w-5",
lockChat
? "animate-pulse text-primary"
: "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>
);
return (
<div className="eraser-column-arrangement">
<div className="eraser-size">
<div className="eraser-position">
<button disabled={lockChat} onClick={() => clearChat()}>
<IconComponent
name="Eraser"
className={classNames(
"h-5 w-5",
lockChat
? "animate-pulse text-primary"
: "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({
text,
emissor,
text,
emissor,
}: {
text: string;
emissor: string;
}) {
return (
<div>
<strong> {emissor}</strong>
<br></br>
<span>{text}</span>
</div>
);
}
text: string;
emissor: string;
}) {
return (
<div>
<strong> {emissor}</strong>
<br></br>
<span>{text}</span>
</div>
);
}

View file

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

View file

@ -678,5 +678,5 @@ export const LANGFLOW_SUPPORTED_TYPES = new Set([
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"]);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,81 +1,85 @@
import { AxiosError } from "axios";
import { FlowType } from "../types/flow";
import { getVerticesOrder, postBuildVertex } from "../controllers/API";
import { FlowType } from "../types/flow";
type BuildVerticesParams = {
flow: FlowType; // Assuming FlowType is the type for your flow
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
onBuildUpdate?: (data: any) => void; // Replace any with the actual type of data
onBuildComplete?: (allNodesValid: boolean) => void;
onBuildError?: (title, list) => void;
};
export async function buildVertices({
flow,
nodeId = null,
onProgressUpdate,
onBuildUpdate,
onBuildComplete,
onBuildError,
}: BuildVerticesParams) {
try {
// Step 1: Get vertices order
console.log(JSON.parse(JSON.stringify(flow)));
let orderResponse = await getVerticesOrder(flow.id);
let verticesOrder = orderResponse.data.ids.flatMap((id) => id);
// Determine the range of vertices to build
let vertexIndex: number | null = null;
if (nodeId) {
vertexIndex = verticesOrder.indexOf(nodeId);
}
let buildRange =
vertexIndex !== null
? verticesOrder.slice(0, vertexIndex + 1)
: verticesOrder;
const buildResults: boolean[] = [];
for (let vertexId of buildRange) {
try {
const buildResponse = await postBuildVertex(flow, vertexId);
const buildData = buildResponse.data;
if (onProgressUpdate) {
const progress =
verticesOrder.indexOf(vertexId) / verticesOrder.length;
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"]);
}
flow: FlowType; // Assuming FlowType is the type for your flow
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
onBuildUpdate?: (data: any) => void; // Replace any with the actual type of data
onBuildComplete?: (allNodesValid: boolean) => void;
onBuildError?: (title, list) => void;
};
export async function buildVertices({
flow,
nodeId = null,
onProgressUpdate,
onBuildUpdate,
onBuildComplete,
onBuildError,
}: BuildVerticesParams) {
try {
// Step 1: Get vertices order
console.log(JSON.parse(JSON.stringify(flow)));
let orderResponse = await getVerticesOrder(flow.id);
let verticesOrder = orderResponse.data.ids.flatMap((id) => id);
// Determine the range of vertices to build
let vertexIndex: number | null = null;
if (nodeId) {
vertexIndex = verticesOrder.indexOf(nodeId);
}
let buildRange =
vertexIndex !== null
? verticesOrder.slice(0, vertexIndex + 1)
: verticesOrder;
const buildResults: boolean[] = [];
for (let vertexId of buildRange) {
try {
const buildResponse = await postBuildVertex(flow, vertexId);
const buildData = buildResponse.data;
if (onProgressUpdate) {
const progress =
verticesOrder.indexOf(vertexId) / verticesOrder.length;
onProgressUpdate(progress);
}
}
// 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 (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) {
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) {
const keys = {};
// 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 key in obj) {
if (keys[key]) {

View file

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