Added global input component to modularize

This commit is contained in:
Lucas Oliveira 2024-03-22 17:18:29 +01:00
commit fe2f30d5c5
5 changed files with 233 additions and 293 deletions

Binary file not shown.

View file

@ -2,17 +2,13 @@ import { cloneDeep } from "lodash";
import React, { ReactNode, useEffect, useRef, useState } from "react";
import { Handle, Position, useUpdateNodeInternals } from "reactflow";
import ShadTooltip from "../../../../components/ShadTooltipComponent";
import AddNewVariableButton from "../../../../components/addNewVariableButtonComponent/addNewVariableButton";
import CodeAreaComponent from "../../../../components/codeAreaComponent";
import DictComponent from "../../../../components/dictComponent";
import Dropdown from "../../../../components/dropdownComponent";
import FloatComponent from "../../../../components/floatComponent";
import {
default as ForwardedIconComponent,
default as IconComponent,
} from "../../../../components/genericIconComponent";
import InputComponent from "../../../../components/inputComponent";
import { default as IconComponent } from "../../../../components/genericIconComponent";
import InputFileComponent from "../../../../components/inputFileComponent";
import InputGlobalComponent from "../../../../components/inputGlobalComponent";
import InputListComponent from "../../../../components/inputListComponent";
import IntComponent from "../../../../components/intComponent";
import KeypairListComponent from "../../../../components/keypairListComponent";
@ -20,7 +16,6 @@ import PromptAreaComponent from "../../../../components/promptComponent";
import TextAreaComponent from "../../../../components/textAreaComponent";
import ToggleShadComponent from "../../../../components/toggleShadComponent";
import { Button } from "../../../../components/ui/button";
import { CommandItem } from "../../../../components/ui/command";
import { RefreshButton } from "../../../../components/ui/refreshButton";
import {
INPUT_HANDLER_HOVER,
@ -28,18 +23,11 @@ import {
OUTPUT_HANDLER_HOVER,
TOOLTIP_EMPTY,
} from "../../../../constants/constants";
import { deleteGlobalVariable } from "../../../../controllers/API";
import DeleteConfirmationModal from "../../../../modals/DeleteConfirmationModal";
import useAlertStore from "../../../../stores/alertStore";
import useFlowStore from "../../../../stores/flowStore";
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
import { useGlobalVariablesStore } from "../../../../stores/globalVariables";
import { useTypesStore } from "../../../../stores/typesStore";
import {
APIClassType,
ResponseErrorDetailAPI,
ResponseErrorTypeAPI,
} from "../../../../types/api";
import { APIClassType, ResponseErrorTypeAPI } from "../../../../types/api";
import { ParameterComponentType } from "../../../../types/components";
import {
handleUpdateValues,
@ -57,7 +45,7 @@ import {
nodeIconsLucide,
nodeNames,
} from "../../../../utils/styleUtils";
import { classNames, cn, groupByFamily } from "../../../../utils/utils";
import { classNames, groupByFamily } from "../../../../utils/utils";
export default function ParameterComponent({
left,
@ -83,49 +71,6 @@ export default function ParameterComponent({
const nodes = useFlowStore((state) => state.nodes);
const edges = useFlowStore((state) => state.edges);
const setNode = useFlowStore((state) => state.setNode);
const globalVariablesEntries = useGlobalVariablesStore(
(state) => state.globalVariablesEntries
);
const getVariableId = useGlobalVariablesStore((state) => state.getVariableId);
const removeGlobalVariable = useGlobalVariablesStore(
(state) => state.removeGlobalVariable
);
function handleDelete(key: string) {
const id = getVariableId(key);
if (id !== undefined) {
deleteGlobalVariable(id)
.then((_) => {
removeGlobalVariable(key);
if (
data?.node?.template[name].value === key &&
data?.node?.template[name].load_from_db
) {
handleOnNewValue("");
setNode(data.id, (oldNode) => {
let newNode = cloneDeep(oldNode);
newNode.data = {
...newNode.data,
};
newNode.data.node.template[name].load_from_db = false;
return newNode;
});
}
})
.catch((error) => {
let responseError = error as ResponseErrorDetailAPI;
setErrorData({
title: "Error deleting variable",
list: [responseError.response.data.detail ?? "Unknown error"],
});
});
} else {
setErrorData({
title: "Error deleting variable",
list: [cn("ID not found for variable: ", key)],
});
}
}
const [isLoading, setIsLoading] = useState(false);
const flow = currentFlow?.data?.nodes ?? null;
@ -169,24 +114,6 @@ export default function ParameterComponent({
renderTooltips();
};
useEffect(() => {
if (data.node?.template[name])
if (
!globalVariablesEntries.includes(data.node?.template[name].value) &&
data.node?.template[name].load_from_db
) {
handleOnNewValue("");
setNode(data.id, (oldNode) => {
let newNode = cloneDeep(oldNode);
newNode.data = {
...newNode.data,
};
newNode.data.node.template[name].load_from_db = false;
return newNode;
});
}
}, [globalVariablesEntries]);
useEffect(() => {
async function fetchData() {
if (
@ -609,80 +536,21 @@ export default function ParameterComponent({
(data.node?.template[name].refresh_button ? "w-5/6" : "")
}
>
<InputComponent
id={"input-" + name}
<InputGlobalComponent
disabled={disabled}
password={data.node?.template[name].password ?? false}
value={data.node?.template[name].value ?? ""}
options={globalVariablesEntries}
optionsPlaceholder={"Global Variables"}
optionsIcon="Globe"
optionsButton={
<AddNewVariableButton>
<CommandItem value="doNotFilter-addNewVariable">
<IconComponent
name="Plus"
className={cn("mr-2 h-4 w-4 text-primary")}
aria-hidden="true"
/>
<span>Add New Variable</span>
</CommandItem>
</AddNewVariableButton>
}
optionButton={(option) => (
<DeleteConfirmationModal
onConfirm={(e) => {
e.stopPropagation();
e.preventDefault();
handleDelete(option);
}}
description={'variable "' + option + '"'}
asChild
>
<button
onClick={(e) => {
e.stopPropagation();
}}
className="pr-1"
>
<ForwardedIconComponent
name="Trash2"
className={cn(
"h-4 w-4 text-primary opacity-0 hover:text-status-red group-hover:opacity-100"
)}
aria-hidden="true"
/>
</button>
</DeleteConfirmationModal>
)}
selectedOption={
data?.node?.template[name].load_from_db ?? false
? data?.node?.template[name].value
: ""
}
setSelectedOption={(value) => {
handleOnNewValue(value);
onChange={handleOnNewValue}
setDb={(value) => {
setNode(data.id, (oldNode) => {
let newNode = cloneDeep(oldNode);
newNode.data = {
...newNode.data,
};
newNode.data.node.template[name].load_from_db =
value === "" ? false : true;
return newNode;
});
}}
onChange={(value) => {
handleOnNewValue(value);
setNode(data.id, (oldNode) => {
let newNode = cloneDeep(oldNode);
newNode.data = {
...newNode.data,
};
newNode.data.node.template[name].load_from_db = false;
newNode.data.node.template[name].load_from_db = value;
return newNode;
});
}}
name={name}
data={data}
/>
</div>
{data.node?.template[name].refresh_button && (

View file

@ -6,7 +6,6 @@ import AccordionComponent from "../../components/AccordionComponent";
import CodeAreaComponent from "../../components/codeAreaComponent";
import Dropdown from "../../components/dropdownComponent";
import FloatComponent from "../../components/floatComponent";
import InputComponent from "../../components/inputComponent";
import InputFileComponent from "../../components/inputFileComponent";
import InputListComponent from "../../components/inputListComponent";
import IntComponent from "../../components/intComponent";
@ -28,10 +27,8 @@ import {
TabsTrigger,
} from "../../components/ui/tabs";
import { LANGFLOW_SUPPORTED_TYPES } from "../../constants/constants";
import useAlertStore from "../../stores/alertStore";
import { useDarkStore } from "../../stores/darkStore";
import useFlowStore from "../../stores/flowStore";
import { useGlobalVariablesStore } from "../../stores/globalVariables";
import { codeTabsPropsType } from "../../types/components";
import {
convertObjToArray,
@ -41,6 +38,7 @@ import {
import { classNames } from "../../utils/utils";
import DictComponent from "../dictComponent";
import IconComponent from "../genericIconComponent";
import InputGlobalComponent from "../inputGlobalComponent";
import KeypairListComponent from "../keypairListComponent";
export default function CodeTabsComponent({
@ -56,10 +54,7 @@ export default function CodeTabsComponent({
const [openAccordion, setOpenAccordion] = useState<string[]>([]);
const dark = useDarkStore((state) => state.dark);
const unselectAll = useFlowStore((state) => state.unselectAll);
const globalVariablesEntries = useGlobalVariablesStore(
(state) => state.globalVariablesEntries
);
const setNoticeData = useAlertStore((state) => state.setNoticeData);
const setNode = useFlowStore((state) => state.setNode);
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
@ -350,63 +345,30 @@ export default function CodeTabsComponent({
/>
</div>
) : (
<InputComponent
options={
globalVariablesEntries
}
editNode={true}
<InputGlobalComponent
disabled={false}
password={
node.data.node.template[
templateField
].password ?? false
}
value={
!node.data.node.template[
templateField
].value ||
node.data.node.template[
templateField
].value === ""
? ""
: node.data.node
.template[
templateField
].value
}
onChange={(target) => {
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList![
i
].data.node.template[
templateField
].value = target;
if (
globalVariablesEntries.includes(
target
)
) {
setNoticeData({
title: `the value inserted in ${templateField} is a global variable, \n
the real value will be update on run`,
});
newInputList![
i
].data.node.template[
templateField
].load_from_db = true;
}
else{
newInputList![
i
].data.node.template[
templateField
].load_from_db = false;
}
return newInputList;
});
if (node.data) {
setNode(
node.data.id,
(oldNode) => {
let newNode =
cloneDeep(
oldNode
);
newNode.data = {
...newNode.data,
};
newNode.data.node.template[
templateField
].value = target;
return newNode;
}
);
}
tweaks.buildTweakObject!(
node["data"]["id"],
target,
@ -415,6 +377,25 @@ export default function CodeTabsComponent({
]
);
}}
setDb={(value) => {
setNode(
node.data.id,
(oldNode) => {
let newNode =
cloneDeep(oldNode);
newNode.data = {
...newNode.data,
};
newNode.data.node.template[
templateField
].load_from_db =
value;
return newNode;
}
);
}}
name={templateField}
data={node.data}
/>
)}
</div>

View file

@ -0,0 +1,131 @@
import { useEffect } from "react";
import { deleteGlobalVariable } from "../../controllers/API";
import DeleteConfirmationModal from "../../modals/DeleteConfirmationModal";
import useAlertStore from "../../stores/alertStore";
import { useGlobalVariablesStore } from "../../stores/globalVariables";
import { ResponseErrorDetailAPI } from "../../types/api";
import { cn } from "../../utils/utils";
import AddNewVariableButton from "../addNewVariableButtonComponent/addNewVariableButton";
import ForwardedIconComponent from "../genericIconComponent";
import InputComponent from "../inputComponent";
import { CommandItem } from "../ui/command";
export default function InputGlobalComponent({
disabled,
onChange,
setDb,
name,
data,
}) {
const globalVariablesEntries = useGlobalVariablesStore(
(state) => state.globalVariablesEntries
);
const getVariableId = useGlobalVariablesStore((state) => state.getVariableId);
const removeGlobalVariable = useGlobalVariablesStore(
(state) => state.removeGlobalVariable
);
const setErrorData = useAlertStore((state) => state.setErrorData);
useEffect(() => {
if (data.node?.template[name])
if (
!globalVariablesEntries.includes(data.node?.template[name].value) &&
data.node?.template[name].load_from_db
) {
onChange("");
setDb(false);
}
}, [globalVariablesEntries]);
function handleDelete(key: string) {
const id = getVariableId(key);
if (id !== undefined) {
deleteGlobalVariable(id)
.then((_) => {
removeGlobalVariable(key);
if (
data?.node?.template[name].value === key &&
data?.node?.template[name].load_from_db
) {
onChange("");
setDb(false);
}
})
.catch((error) => {
let responseError = error as ResponseErrorDetailAPI;
setErrorData({
title: "Error deleting variable",
list: [responseError.response.data.detail ?? "Unknown error"],
});
});
} else {
setErrorData({
title: "Error deleting variable",
list: [cn("ID not found for variable: ", key)],
});
}
}
return (
<InputComponent
id={"input-" + name}
disabled={disabled}
password={data.node?.template[name].password ?? false}
value={data.node?.template[name].value ?? ""}
options={globalVariablesEntries}
optionsPlaceholder={"Global Variables"}
optionsIcon="Globe"
optionsButton={
<AddNewVariableButton>
<CommandItem value="doNotFilter-addNewVariable">
<ForwardedIconComponent
name="Plus"
className={cn("mr-2 h-4 w-4 text-primary")}
aria-hidden="true"
/>
<span>Add New Variable</span>
</CommandItem>
</AddNewVariableButton>
}
optionButton={(option) => (
<DeleteConfirmationModal
onConfirm={(e) => {
e.stopPropagation();
e.preventDefault();
handleDelete(option);
}}
description={'variable "' + option + '"'}
asChild
>
<button
onClick={(e) => {
e.stopPropagation();
}}
className="pr-1"
>
<ForwardedIconComponent
name="Trash2"
className={cn(
"h-4 w-4 text-primary opacity-0 hover:text-status-red group-hover:opacity-100"
)}
aria-hidden="true"
/>
</button>
</DeleteConfirmationModal>
)}
selectedOption={
data?.node?.template[name].load_from_db ?? false
? data?.node?.template[name].value
: ""
}
setSelectedOption={(value) => {
onChange(value);
setDb(value !== "" ? true : false);
}}
onChange={(value) => {
onChange(value);
setDb(false);
}}
/>
);
}

View file

@ -6,8 +6,8 @@ import DictComponent from "../../components/dictComponent";
import Dropdown from "../../components/dropdownComponent";
import FloatComponent from "../../components/floatComponent";
import IconComponent from "../../components/genericIconComponent";
import InputComponent from "../../components/inputComponent";
import InputFileComponent from "../../components/inputFileComponent";
import InputGlobalComponent from "../../components/inputGlobalComponent";
import InputListComponent from "../../components/inputListComponent";
import IntComponent from "../../components/intComponent";
import KeypairListComponent from "../../components/keypairListComponent";
@ -162,11 +162,11 @@ const EditNodeModal = forwardRef(
scapedJSONStringfy(
myData.node!.template[templateParam].proxy
? {
...id,
proxy:
myData.node?.template[templateParam]
.proxy,
}
...id,
proxy:
myData.node?.template[templateParam]
.proxy,
}
: id
)
) ?? false;
@ -189,7 +189,7 @@ const EditNodeModal = forwardRef(
content={
myData.node?.template[templateParam].proxy
? myData.node?.template[templateParam]
.proxy?.id
.proxy?.id
: null
}
>
@ -197,16 +197,16 @@ const EditNodeModal = forwardRef(
{myData.node?.template[templateParam]
.display_name
? myData.node.template[templateParam]
.display_name
.display_name
: myData.node?.template[templateParam]
.name}
.name}
</span>
</ShadTooltip>
</TableCell>
<TableCell className="w-[300px] p-0 text-center text-xs text-foreground ">
{myData.node?.template[templateParam].type ===
"str" &&
!myData.node.template[templateParam].options ? (
!myData.node.template[templateParam].options ? (
<div className="mx-auto">
{myData.node.template[templateParam]
.list ? (
@ -216,12 +216,12 @@ const EditNodeModal = forwardRef(
value={
!myData.node.template[templateParam]
.value ||
myData.node.template[templateParam]
.value === ""
myData.node.template[templateParam]
.value === ""
? [""]
: myData.node.template[
templateParam
].value
templateParam
].value
}
onChange={(value: string[]) => {
handleOnNewValue(
@ -231,7 +231,7 @@ const EditNodeModal = forwardRef(
}}
/>
) : myData.node.template[templateParam]
.multiline ? (
.multiline ? (
<TextAreaComponent
id={
"textarea-edit-" +
@ -259,67 +259,27 @@ const EditNodeModal = forwardRef(
}}
/>
) : (
<InputComponent
id={
"input-" +
myData.node.template[templateParam]
.name
}
editNode={true}
options={globalVariablesEntries}
<InputGlobalComponent
disabled={disabled}
password={
myData.node.template[templateParam]
.password ?? false
onChange={(value) =>
handleOnNewValue(value, templateParam)
}
value={
myData.node.template[templateParam]
.value ?? ""
}
onChange={(value) => {
handleOnNewValue(
value,
templateParam
);
if (
globalVariablesEntries.includes(
value
)
) {
setNoticeData({
title: `the value inserted in ${data.node?.display_name} is a global variable, \n
the real value will be update on run`,
});
//mark as global variable
setNode(data.id, (oldNode) => {
let newNode = cloneDeep(oldNode);
newNode.data = {
...newNode.data,
};
newNode.data.node.template[
templateParam
].load_from_db = true;
return newNode;
});
}
else {
setNode(data.id, (oldNode) => {
let newNode = cloneDeep(oldNode);
newNode.data = {
...newNode.data,
};
newNode.data.node.template[
templateParam
].load_from_db = false;
return newNode;
});
}
setDb={(value) => {
setMyData((oldData) => {
let newData = cloneDeep(oldData);
newData.node!.template[
templateParam
].load_from_db = value;
return newData;
});
}}
name={templateParam}
data={myData}
/>
)}
</div>
) : myData.node?.template[templateParam]
.type === "NestedDict" ? (
.type === "NestedDict" ? (
<div className=" w-full">
<DictComponent
disabled={disabled}
@ -329,10 +289,10 @@ const EditNodeModal = forwardRef(
templateParam
]?.value?.toString() === "{}"
? {
yourkey: "value",
}
yourkey: "value",
}
: myData.node!.template[templateParam]
.value
.value
}
onChange={(newValue) => {
myData.node!.template[
@ -347,7 +307,7 @@ const EditNodeModal = forwardRef(
/>
</div>
) : myData.node?.template[templateParam]
.type === "dict" ? (
.type === "dict" ? (
<div
className={classNames(
"max-h-48 w-full overflow-auto custom-scroll",
@ -363,14 +323,14 @@ const EditNodeModal = forwardRef(
value={
myData.node!.template[templateParam]
.value?.length === 0 ||
!myData.node!.template[templateParam]
.value
!myData.node!.template[templateParam]
.value
? [{ "": "" }]
: convertObjToArray(
myData.node!.template[
templateParam
].value
)
myData.node!.template[
templateParam
].value
)
}
duplicateKey={errorDuplicateKey}
onChange={(newValue) => {
@ -390,7 +350,7 @@ const EditNodeModal = forwardRef(
/>
</div>
) : myData.node?.template[templateParam]
.type === "bool" ? (
.type === "bool" ? (
<div className="ml-auto">
{" "}
<ToggleShadComponent
@ -414,7 +374,7 @@ const EditNodeModal = forwardRef(
/>
</div>
) : myData.node?.template[templateParam]
.type === "float" ? (
.type === "float" ? (
<div className="mx-auto">
<FloatComponent
disabled={disabled}
@ -433,7 +393,7 @@ const EditNodeModal = forwardRef(
/>
</div>
) : myData.node?.template[templateParam]
.type === "str" &&
.type === "str" &&
myData.node.template[templateParam]
.options ? (
<div className="mx-auto">
@ -458,7 +418,7 @@ const EditNodeModal = forwardRef(
></Dropdown>
</div>
) : myData.node?.template[templateParam]
.type === "int" ? (
.type === "int" ? (
<div className="mx-auto">
<IntComponent
id={
@ -477,7 +437,7 @@ const EditNodeModal = forwardRef(
/>
</div>
) : myData.node?.template[templateParam]
.type === "file" ? (
.type === "file" ? (
<div className="mx-auto">
<InputFileComponent
editNode={true}
@ -501,7 +461,7 @@ const EditNodeModal = forwardRef(
></InputFileComponent>
</div>
) : myData.node?.template[templateParam]
.type === "prompt" ? (
.type === "prompt" ? (
<div className="mx-auto">
<PromptAreaComponent
readonly={
@ -532,13 +492,13 @@ const EditNodeModal = forwardRef(
/>
</div>
) : myData.node?.template[templateParam]
.type === "code" ? (
.type === "code" ? (
<div className="mx-auto">
<CodeAreaComponent
readonly={
myData.node?.flow &&
myData.node.template[templateParam]
.dynamic
myData.node.template[templateParam]
.dynamic
? true
: false
}
@ -566,7 +526,7 @@ const EditNodeModal = forwardRef(
/>
</div>
) : myData.node?.template[templateParam]
.type === "Any" ? (
.type === "Any" ? (
"-"
) : (
<div className="hidden"></div>