Merge branch 'zustand/io/migration' of personal:logspace-ai/langflow into zustand/io/migration

This commit is contained in:
anovazzi1 2024-03-06 15:01:45 -03:00
commit b388873d1b
101 changed files with 1193 additions and 1295 deletions

View file

@ -23,14 +23,16 @@ import {
OUTPUT_HANDLER_HOVER,
TOOLTIP_EMPTY,
} from "../../../../constants/constants";
import { postCustomComponentUpdate } from "../../../../controllers/API";
import useAlertStore from "../../../../stores/alertStore";
import useFlowStore from "../../../../stores/flowStore";
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
import { useTypesStore } from "../../../../stores/typesStore";
import { APIClassType } from "../../../../types/api";
import { APIClassType, ResponseErrorTypeAPI } from "../../../../types/api";
import { ParameterComponentType } from "../../../../types/components";
import { NodeDataType } from "../../../../types/flow";
import {
handleUpdateValues,
throttledHandleUpdateValues,
} from "../../../../utils/parameterUtils";
import {
convertObjToArray,
convertValuesToNumbers,
@ -86,81 +88,70 @@ export default function ParameterComponent({
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
const handleUpdateValues = async (
name: string,
data: NodeDataType,
delayAnimation: boolean = true
) => {
setIsLoading(true);
const code = data.node?.template["code"]?.value;
if (!code) {
console.error("Code not found in the template");
return;
}
await postCustomComponentUpdate(
code,
name,
data.node?.template[name]?.value
)
.then((res) => {
if (res.status === 200 && data.node?.template) {
setNode(data.id, (oldNode) => {
let newNode = cloneDeep(oldNode);
newNode.data = {
...newNode.data,
};
newNode.data.node.template = res.data.template;
return newNode;
});
}
})
.catch((error) => {
console.error("Error occurred while updating the node:", error);
setErrorData({
title: "Error while updating the Component",
list: [error.response.data.detail.error ?? "Unknown error"],
});
});
renderTooltips();
if (delayAnimation) {
try {
// Wait for at least 500 milliseconds
await new Promise((resolve) => setTimeout(resolve, 500));
// Continue with the request
// If the request takes longer than 500 milliseconds, it will not wait an additional 500 milliseconds
} catch (error) {
console.error("Error occurred while waiting for refresh:", error);
} finally {
setIsLoading(false);
}
} else setIsLoading(false);
};
useEffect(() => {
function fetchData() {
async function fetchData() {
if (
data.node?.template[name]?.refresh &&
Object.keys(data.node?.template[name]?.options ?? {}).length === 0
// options can be undefined but not an empty array
(data.node?.template[name]?.options?.length ?? 0) === 0
) {
handleUpdateValues(name, data, false);
setIsLoading(true);
try {
let newTemplate = await handleUpdateValues(name, data);
if (newTemplate) {
setNode(data.id, (oldNode) => {
let newNode = cloneDeep(oldNode);
newNode.data = {
...newNode.data,
};
newNode.data.node.template = newTemplate;
return newNode;
});
}
} catch (error) {
let responseError = error as ResponseErrorTypeAPI;
setErrorData({
title: "Error while updating the Component",
list: [responseError.response.data.detail.error ?? "Unknown error"],
});
}
setIsLoading(false);
renderTooltips();
}
}
fetchData();
}, []);
const handleOnNewValue = (
const handleOnNewValue = async (
newValue: string | string[] | boolean | Object[]
): void => {
): Promise<void> => {
if (data.node!.template[name].value !== newValue) {
takeSnapshot();
}
const shouldUpdate =
data.node?.template[name].refresh &&
data.node!.template[name].value !== newValue;
console.log("shouldUpdate", shouldUpdate);
console.log(
"data.node!.template[name].value",
data.node!.template[name].value
);
console.log("newValue", newValue);
data.node!.template[name].value = newValue; // necessary to enable ctrl+z inside the input
let newTemplate;
if (shouldUpdate) {
setIsLoading(true);
try {
newTemplate = await throttledHandleUpdateValues(name, data);
} catch (error) {
let responseError = error as ResponseErrorTypeAPI;
setErrorData({
title: "Error while updating the Component",
list: [responseError.response.data.detail.error ?? "Unknown error"],
});
}
setIsLoading(false);
// this de
}
setNode(data.id, (oldNode) => {
let newNode = cloneDeep(oldNode);
@ -168,7 +159,9 @@ export default function ParameterComponent({
...newNode.data,
};
newNode.data.node.template[name].value = newValue;
if (data.node?.template[name].refresh && newTemplate) {
newNode.data.node.template = newTemplate;
} else newNode.data.node.template[name].value = newValue;
return newNode;
});
@ -300,11 +293,14 @@ export default function ParameterComponent({
refHtml.current = <span>{TOOLTIP_EMPTY}</span>;
}
}
// If optionalHandle is an empty list, then it is not an optional handle
if (optionalHandle && optionalHandle.length === 0) {
optionalHandle = null;
}
useEffect(() => {
renderTooltips();
}, [tooltipTitle, flow]);
return !showNode ? (
left && LANGFLOW_SUPPORTED_TYPES.has(type ?? "") && !optionalHandle ? (
<></>
@ -451,7 +447,9 @@ export default function ParameterComponent({
{data.node?.template[name].list ? (
<div
className={
(data.node?.template[name].refresh ? "w-5/6 " : "") +
// Commenting this out until we have a better
// way to display
// (data.node?.template[name].refresh ? "w-5/6 " : "") +
"flex-grow"
}
>
@ -465,7 +463,7 @@ export default function ParameterComponent({
}
onChange={handleOnNewValue}
/>
{data.node?.template[name].refresh && (
{/* {data.node?.template[name].refresh && (
<div className="w-1/6">
<RefreshButton
isLoading={isLoading}
@ -477,7 +475,7 @@ export default function ParameterComponent({
id={"refresh-button-" + name}
/>
</div>
)}
)} */}
</div>
) : data.node?.template[name].multiline ? (
<TextAreaComponent
@ -489,7 +487,12 @@ export default function ParameterComponent({
/>
) : (
<div className="mt-2 flex w-full items-center">
<div className="w-5/6 flex-grow">
<div
className={
"flex-grow " +
(data.node?.template[name].refresh ? "w-5/6" : "")
}
>
<InputComponent
id={"input-" + name}
disabled={disabled}
@ -648,8 +651,14 @@ export default function ParameterComponent({
onChange={(newValue) => {
const valueToNumbers = convertValuesToNumbers(newValue);
setErrorDuplicateKey(hasDuplicateKeys(valueToNumbers));
handleOnNewValue(valueToNumbers);
// if data.node?.template[name].list is true, then the value is an array of objects
// else we need to get the first object of the array
if (data.node?.template[name].list) {
handleOnNewValue(valueToNumbers);
} else handleOnNewValue(valueToNumbers[0]);
}}
isList={data.node?.template[name].list ?? false}
/>
</div>
) : (

View file

@ -50,9 +50,7 @@ export default function AccordionComponent({
{trigger}
</AccordionTrigger>
<AccordionContent>
<div className="AccordionContent flex flex-col">
{children}
</div>
<div className="AccordionContent flex flex-col">{children}</div>
</AccordionContent>
</AccordionItem>
</Accordion>

View file

@ -26,7 +26,7 @@ export default function CrashErrorComponent({
<CardContent className="grid">
<div>
<p>
Please report errors with detailed tracebacks on the{" "}
Please report errors with detailed tracebacks on the{" "}
<a
href="https://github.com/logspace-ai/langflow/issues"
target="_blank"
@ -37,7 +37,7 @@ export default function CrashErrorComponent({
</a>{" "}
page.
<br></br>
Thank you!
Thank you!
</p>
</div>
</CardContent>

View file

@ -1,54 +1,33 @@
import { useEffect, useState } from "react";
import { getComponent, postLikeComponent } from "../../controllers/API";
import DeleteConfirmationModal from "../../modals/DeleteConfirmationModal";
import useAlertStore from "../../stores/alertStore";
import useFlowsManagerStore from "../../stores/flowsManagerStore";
import { useStoreStore } from "../../stores/storeStore";
import { storeComponent } from "../../types/store";
import cloneFLowWithParent from "../../utils/storeUtils";
import { cn } from "../../utils/utils";
import ShadTooltip from "../ShadTooltipComponent";
import IconComponent from "../genericIconComponent";
import { Badge } from "../ui/badge";
import { Button } from "../ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "../ui/card";
import { FlowType } from "../../types/flow";
import { useNavigate } from "react-router-dom";
import useFlowsManagerStore from "../../stores/flowsManagerStore";
import { cn } from "../../utils/utils";
import IconComponent from "../genericIconComponent";
import { Card, CardContent } from "../ui/card";
export default function NewFlowCardComponent({
}: {
}) {
const addFlow = useFlowsManagerStore((state) => state.addFlow);
const navigate = useNavigate();
export default function NewFlowCardComponent({}: {}) {
const addFlow = useFlowsManagerStore((state) => state.addFlow);
const navigate = useNavigate();
return (
<Card
className={cn(
"group relative h-48 w-2/6 flex flex-col justify-between overflow-hidden transition-all hover:shadow-md",
)}
return (
<Card
className={cn(
"group relative flex h-48 w-2/6 flex-col justify-between overflow-hidden transition-all hover:shadow-md"
)}
>
<CardContent className="flex h-full w-full items-center justify-center align-middle">
<button
onClick={() => {
addFlow(true).then((id) => {
navigate("/flow/" + id);
});
}}
>
<CardContent className="w-full h-full flex align-middle items-center justify-center">
<button onClick={() => {
addFlow(true).then((id) => {
navigate("/flow/" + id);
});
}}>
<IconComponent
className={cn(
"h-12 w-12 text-muted-foreground",
)}
name="PlusCircle"
/>
</button>
</CardContent>
</Card>
);
<IconComponent
className={cn("h-12 w-12 text-muted-foreground")}
name="PlusCircle"
/>
</button>
</CardContent>
</Card>
);
}

View file

@ -126,7 +126,7 @@ export default function CodeTabsComponent({
<Tabs
value={activeTab}
className={
"api-modal-tabs m-0 inset-0 " +
"api-modal-tabs inset-0 m-0 " +
(isMessage ? "dark " : "") +
(dark && isMessage ? "bg-background" : "")
}
@ -195,7 +195,7 @@ export default function CodeTabsComponent({
<SyntaxHighlighter
language={tab.language}
style={oneDark}
className="mt-0 h-full overflow-auto custom-scroll rounded-sm text-left"
className="mt-0 h-full overflow-auto rounded-sm text-left custom-scroll"
>
{tab.code}
</SyntaxHighlighter>

View file

@ -1,15 +1,10 @@
import { useEffect, useState } from "react";
import { getComponent, postLikeComponent } from "../../controllers/API";
import DeleteConfirmationModal from "../../modals/DeleteConfirmationModal";
import useAlertStore from "../../stores/alertStore";
import { useNavigate } from "react-router-dom";
import useFlowsManagerStore from "../../stores/flowsManagerStore";
import { useStoreStore } from "../../stores/storeStore";
import { storeComponent } from "../../types/store";
import cloneFLowWithParent from "../../utils/storeUtils";
import { FlowType } from "../../types/flow";
import { updateIds } from "../../utils/reactflowUtils";
import { cn } from "../../utils/utils";
import ShadTooltip from "../ShadTooltipComponent";
import IconComponent from "../genericIconComponent";
import { Badge } from "../ui/badge";
import { Button } from "../ui/button";
import {
Card,
@ -18,20 +13,17 @@ import {
CardHeader,
CardTitle,
} from "../ui/card";
import { FlowType } from "../../types/flow";
import { updateIds } from "../../utils/reactflowUtils";
import { useNavigate } from "react-router-dom";
export default function CollectionCardComponent({
flow,
flow,
}: {
flow: FlowType;
authorized?: boolean;
flow: FlowType;
authorized?: boolean;
}) {
const addFlow = useFlowsManagerStore((state) => state.addFlow);
const navigate = useNavigate();
const emojiRegex = /\p{Emoji}/u;
const isEmoji= (str:string)=> emojiRegex.test(str);
const isEmoji = (str: string) => emojiRegex.test(str);
return (
<Card
@ -43,20 +35,17 @@ export default function CollectionCardComponent({
<CardHeader>
<div>
<CardTitle className="flex w-full items-center justify-between gap-3 text-xl">
{flow.icon && isEmoji(flow.icon) && (
<div className="rounded-md p-2 flex align-middle items-center justify-center" style={{backgroundColor:flow.icon_bg_color}}>
<div className="pl-0.5 h-7 w-7">
{flow.icon}
</div>
{flow.icon && (
<div className="flex-shrink-0 h-7 w-7">
{flow.icon}
</div>
)}
{(!flow.icon || !isEmoji(flow.icon)) && <IconComponent
{!flow.icon && <IconComponent
className={cn(
"flex-shrink-0 h-7 w-7 text-flow-icon",
)}
name={flow.icon || "Group"}
name="Group"
/>}
<ShadTooltip content={flow.name}>
<div className="w-full truncate">{flow.name}</div>
@ -73,12 +62,11 @@ export default function CollectionCardComponent({
<CardFooter>
<div className="flex w-full items-center justify-between gap-2">
<div className="flex w-full justify-end flex-wrap gap-2">
<div className="flex w-full flex-wrap justify-end gap-2">
<Button
onClick={() => {
updateIds(flow.data!)
updateIds(flow.data!);
addFlow(true, flow).then((id) => {
navigate("/flow/" + id);
});
}}

View file

@ -12,10 +12,11 @@ export default function KeypairListComponent({
disabled,
editNode = false,
duplicateKey,
isList = true,
}: KeyPairListComponentType): JSX.Element {
useEffect(() => {
if (disabled && value.length > 0 && value[0] !== "") {
onChange([""]);
onChange([{ "": "" }]);
}
}, [disabled]);
@ -79,6 +80,7 @@ export default function KeypairListComponent({
: "keypair" + (index + 100).toString()
}
type="text"
disabled={disabled}
value={obj[key]}
className={editNode ? "input-edit-node" : ""}
placeholder="Type a value..."
@ -87,7 +89,7 @@ export default function KeypairListComponent({
}
/>
{index === ref.current.length - 1 ? (
{isList && index === ref.current.length - 1 ? (
<button
onClick={() => {
let newInputList = _.cloneDeep(ref.current);
@ -110,7 +112,7 @@ export default function KeypairListComponent({
className={"h-4 w-4 hover:text-accent-foreground"}
/>
</button>
) : (
) : isList ? (
<button
onClick={() => {
let newInputList = _.cloneDeep(ref.current);
@ -133,6 +135,8 @@ export default function KeypairListComponent({
className="h-4 w-4 hover:text-status-red"
/>
</button>
) : (
""
)}
</div>
);

View file

@ -134,7 +134,7 @@ export default function ChatMessage({
)}
</div>
{!chat.isSend ? (
<div className="form-modal-chat-text-position flex-grow min-w-96">
<div className="form-modal-chat-text-position min-w-96 flex-grow">
<div className="form-modal-chat-text">
{hidden && chat.thought && chat.thought !== "" && (
<div
@ -155,9 +155,9 @@ export default function ChatMessage({
/>
)}
{chat.thought && chat.thought !== "" && !hidden && <br></br>}
<div className="w-full flex flex-col">
<div className="w-full flex flex-col dark:text-white">
<div className="w-full flex flex-col">
<div className="flex w-full flex-col">
<div className="flex w-full flex-col dark:text-white">
<div className="flex w-full flex-col">
{useMemo(
() =>
chatMessage === "" && lockChat ? (
@ -169,7 +169,7 @@ export default function ChatMessage({
<Markdown
remarkPlugins={[remarkGfm, remarkMath]}
rehypePlugins={[rehypeMathjax]}
className="markdown flex flex-col prose text-primary word-break-break-word
className="markdown prose flex flex-col text-primary word-break-break-word
dark:prose-invert"
components={{
pre({ node, ...props }) {

View file

@ -43,7 +43,7 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={cn(
"flex flex-col fixed left-[50%] top-[50%] z-50 w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full",
"fixed left-[50%] top-[50%] z-50 flex w-full max-w-lg translate-x-[-50%] translate-y-[-50%] flex-col gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full",
className
)}
{...props}

View file

@ -58,4 +58,3 @@ export const FLOW_BUILD_SUCCESS_ALERT = `Flow built successfully`;
export const SAVE_SUCCESS_ALERT = "Changes saved successfully!";
// Generic Node

View file

@ -737,4 +737,5 @@ export const PRIORITY_SIDEBAR_ORDER = [
"prompt",
"models",
"helpers",
"experimental",
];

View file

@ -35,8 +35,7 @@ export default function DeleteConfirmationModal({
</DialogTitle>
</DialogHeader>
<span>
Confirm deletion of {description ?? "component"}?
<br></br>
Confirm deletion of {description ?? "component"}?<br></br>
Note: This action is irreversible.
</span>
<DialogFooter>

View file

@ -165,8 +165,19 @@ const EditNodeModal = forwardRef(
)
) ?? false;
return (
<TableRow key={index} className={"h-10 " + ((templateParam==="code" && myData.node?.template[templateParam].type==="code") || (templateParam.includes("code") && myData.node?.template[templateParam].proxy) ? " hidden " : "")
}>
<TableRow
key={index}
className={
"h-10 " +
((templateParam === "code" &&
myData.node?.template[templateParam].type ===
"code") ||
(templateParam.includes("code") &&
myData.node?.template[templateParam].proxy)
? " hidden "
: "")
}
>
<TableCell className="truncate p-0 text-center text-sm text-foreground sm:px-3">
<ShadTooltip
content={

View file

@ -24,6 +24,7 @@ import { postCustomComponent, postValidateCode } from "../../controllers/API";
import useAlertStore from "../../stores/alertStore";
import { useDarkStore } from "../../stores/darkStore";
import useFlowStore from "../../stores/flowStore";
import { CodeErrorDataTypeAPI } from "../../types/api";
import { codeAreaModalPropsType } from "../../types/components";
import BaseModal from "../baseModal";
@ -50,7 +51,7 @@ export default function CodeAreaModal({
const setSuccessData = useAlertStore((state) => state.setSuccessData);
const setErrorData = useAlertStore((state) => state.setErrorData);
const [error, setError] = useState<{
detail: { error: string | undefined; traceback: string | undefined };
detail: CodeErrorDataTypeAPI;
} | null>(null);
useEffect(() => {

View file

@ -179,7 +179,7 @@ export default function ShareModal({
</span>
<br></br>
<span className=" text-xs text-destructive ">
Note: This action is irreversible.
Note: This action is irreversible.
</span>
</ConfirmationModal.Content>
</ConfirmationModal>
@ -204,7 +204,9 @@ export default function ShareModal({
{children ? children : <></>}
</BaseModal.Trigger>
<BaseModal.Header
description={`Publish ${is_component ? "your component" : "workflow"} to the Langflow Store.`}
description={`Publish ${
is_component ? "your component" : "workflow"
} to the Langflow Store.`}
>
<span className="pr-2">Share</span>
<IconComponent
@ -239,7 +241,8 @@ export default function ShareModal({
</label>
</div>
<span className=" text-xs text-destructive ">
<b>Attention:</b> API keys in specified fields are automatically removed upon sharing.
<b>Attention:</b> API keys in specified fields are automatically
removed upon sharing.
</span>
</BaseModal.Content>

View file

@ -14,7 +14,6 @@ import {
import useAlertStore from "../../../../stores/alertStore";
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
import { FlowType } from "../../../../types/flow";
import { STARTER_FOLDER_NAME } from "../../../../constants/constants";
export default function ComponentsComponent({
is_component = true,

View file

@ -2,6 +2,8 @@ import { Group, ToyBrick } from "lucide-react";
import { useEffect, useState } from "react";
import { Outlet, useLocation, useNavigate } from "react-router-dom";
import DropdownButton from "../../components/DropdownButtonComponent";
import NewFlowCardComponent from "../../components/NewFlowCardComponent";
import ExampleCardComponent from "../../components/exampleComponent";
import IconComponent from "../../components/genericIconComponent";
import PageLayout from "../../components/pageLayout";
import SidebarNav from "../../components/sidebarComponent";
@ -11,12 +13,10 @@ import {
MY_COLLECTION_DESC,
USER_PROJECTS_HEADER,
} from "../../constants/constants";
import BaseModal from "../../modals/baseModal";
import useAlertStore from "../../stores/alertStore";
import useFlowsManagerStore from "../../stores/flowsManagerStore";
import { downloadFlows } from "../../utils/reactflowUtils";
import BaseModal from "../../modals/baseModal";
import ExampleCardComponent from "../../components/exampleComponent";
import NewFlowCardComponent from "../../components/NewFlowCardComponent";
export default function HomePage(): JSX.Element {
const addFlow = useFlowsManagerStore((state) => state.addFlow);
const uploadFlow = useFlowsManagerStore((state) => state.uploadFlow);
@ -41,8 +41,9 @@ export default function HomePage(): JSX.Element {
})
.then((id) => {
setSuccessData({
title: `${is_component ? "Component" : "Flow"
} uploaded successfully`,
title: `${
is_component ? "Component" : "Flow"
} uploaded successfully`,
});
if (!is_component) navigate("/flow/" + id);
})
@ -117,24 +118,25 @@ export default function HomePage(): JSX.Element {
</div>
</div>
<BaseModal open={openModal} setOpen={setOpenModal}>
<BaseModal.Header description={"Select a template or start from scratch"}>
<BaseModal.Header
description={"Select a template or start from scratch"}
>
<span className="pr-2" data-testid="modal-title">
Create a New Flow
</span>
<IconComponent
name="Group"
className="h-6 w-6 text-primary stroke-2 "
className="h-6 w-6 stroke-2 text-primary "
aria-hidden="true"
/>
</BaseModal.Header>
<BaseModal.Content>
<div className="flex flex-wrap w-full h-full p-4 gap-3 overflow-auto custom-scroll">
<div className="flex h-full w-full flex-wrap gap-3 overflow-auto p-4 custom-scroll">
{examples.map((example, idx) => {
return(
<ExampleCardComponent key={idx} flow={example} />)
return <ExampleCardComponent key={idx} flow={example} />;
})}
<NewFlowCardComponent/>
</div>
<NewFlowCardComponent />
</div>
</BaseModal.Content>
</BaseModal>
</PageLayout>

View file

@ -2,6 +2,7 @@ import { AxiosError } from "axios";
import { cloneDeep } from "lodash";
import { Edge, Node, Viewport, XYPosition } from "reactflow";
import { create } from "zustand";
import { STARTER_FOLDER_NAME } from "../constants/constants";
import {
deleteFlowFromDatabase,
readFlowsFromDatabase,
@ -25,7 +26,6 @@ import useAlertStore from "./alertStore";
import { useDarkStore } from "./darkStore";
import useFlowStore from "./flowStore";
import { useTypesStore } from "./typesStore";
import { STARTER_FOLDER_NAME } from "../constants/constants";
let saveTimeoutId: NodeJS.Timeout | null = null;
@ -38,7 +38,7 @@ const past = {};
const future = {};
const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
examples:[],
examples: [],
setExamples: (examples: FlowType[]) => {
set({ examples });
},
@ -67,8 +67,16 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
.then((dbData) => {
if (dbData) {
const { data, flows } = processFlows(dbData, false);
get().setExamples(flows.filter(f=>(f.folder===STARTER_FOLDER_NAME && !f.user_id)));
get().setFlows(flows.filter(f=>!(f.folder===STARTER_FOLDER_NAME && !f.user_id)));
get().setExamples(
flows.filter(
(f) => f.folder === STARTER_FOLDER_NAME && !f.user_id
)
);
get().setFlows(
flows.filter(
(f) => !(f.folder === STARTER_FOLDER_NAME && !f.user_id)
)
);
useTypesStore.setState((state) => ({
data: { ...state.data, ["saved_components"]: data },
}));

View file

@ -159,3 +159,17 @@ export type VertexDataTypeAPI = {
timedelta?: number;
duration?: string;
};
export type CodeErrorDataTypeAPI = {
error: string | undefined;
traceback: string | undefined;
};
// the error above is inside this error.response.data.detail.error
// which comes from a request to the API
// to type the error we need to know the structure of the object
// error that has a response, that has a data, that has a detail, that has an error
export type ResponseErrorTypeAPI = {
response: { data: { detail: CodeErrorDataTypeAPI } };
};

View file

@ -15,8 +15,8 @@ export type FlowType = {
parent?: string;
folder?: string;
user_id?: string;
icon?:string;
icon_bg_color?:string;
icon?: string;
icon_bg_color?: string;
};
export type NodeType = {

View file

@ -0,0 +1,35 @@
import { throttle } from "lodash";
import { postCustomComponentUpdate } from "../controllers/API";
import { ResponseErrorTypeAPI } from "../types/api";
import { NodeDataType } from "../types/flow";
export const handleUpdateValues = async (name: string, data: NodeDataType) => {
const code = data.node?.template["code"]?.value;
if (!code) {
console.error("Code not found in the template");
return;
}
try {
let newTemplate = await postCustomComponentUpdate(
code,
name,
data.node?.template[name]?.value
)
.then((res) => {
console.log("res", res);
if (res.status === 200 && data.node?.template) {
return res.data.template;
}
})
.catch((error) => {
throw error;
});
return newTemplate;
} catch (error) {
console.error("Error occurred while updating the node:", error);
let errorType = error as ResponseErrorTypeAPI;
throw errorType;
}
};
export const throttledHandleUpdateValues = throttle(handleUpdateValues, 10);

View file

@ -231,6 +231,7 @@ export const nodeColors: { [char: string]: string } = {
toolkits: "#DB2C2C",
wrappers: "#E6277A",
helpers: "#31A3CC",
experimental: "#E6277A",
langchain_utilities: "#31A3CC",
output_parsers: "#E6A627",
str: "#31a3cc",
@ -262,6 +263,7 @@ export const nodeNames: { [char: string]: string } = {
textsplitters: "Text Splitters",
retrievers: "Retrievers",
helpers: "Helpers",
experimental: "Experimental",
langchain_utilities: "Utilities",
output_parsers: "Output Parsers",
custom_components: "Custom",
@ -354,6 +356,7 @@ export const nodeIconsLucide: iconsType = {
textsplitters: Scissors,
wrappers: Gift,
helpers: Wand2,
experimental: FlaskConical,
langchain_utilities: PocketKnife,
WolframAlphaAPIWrapper: SvgWolfram,
output_parsers: Compass,

View file

@ -87,7 +87,7 @@ module.exports = {
"beta-foreground": "var(--beta-foreground)",
"chat-bot-icon": "var(--chat-bot-icon)",
"chat-user-icon": "var(--chat-user-icon)",
"ice": "var(--ice)",
ice: "var(--ice)",
white: "var(--white)",
border: "hsl(var(--border))",

File diff suppressed because one or more lines are too long