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[
if (node.data) {
setNode(
node.data.id,
(oldNode) => {
let newNode =
cloneDeep(
oldNode
);
newNode.data = {
...newNode.data,
};
newNode.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;
return newNode;
}
else{
newInputList![
i
].data.node.template[
templateField
].load_from_db = false;
);
}
return newInputList;
});
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";
@ -259,62 +259,22 @@ 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,
setDb={(value) => {
setMyData((oldData) => {
let newData = cloneDeep(oldData);
newData.node!.template[
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`,
].load_from_db = value;
return newData;
});
//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;
});
}
}}
name={templateParam}
data={myData}
/>
)}
</div>