Added cell renderer to render all of the possible parameter types

This commit is contained in:
Lucas Oliveira 2024-06-05 12:41:17 -03:00
commit da2e74a3e7
2 changed files with 353 additions and 565 deletions

View file

@ -0,0 +1,300 @@
import { CustomCellRendererProps } from "ag-grid-react";
import { classNames, cn, isTimeStampString } from "../../utils/utils";
import ArrayReader from "../arrayReaderComponent";
import DateReader from "../dateReaderComponent";
import NumberReader from "../numberReader";
import ObjectRender from "../objectRender";
import StringReader from "../stringReaderComponent";
import { Badge } from "../ui/badge";
import { cloneDeep } from "lodash";
import { type } from "os";
import {
convertObjToArray,
convertValuesToNumbers,
hasDuplicateKeys,
scapedJSONStringfy,
} from "../../utils/reactflowUtils";
import CodeAreaComponent from "../codeAreaComponent";
import DictComponent from "../dictComponent";
import Dropdown from "../dropdownComponent";
import FloatComponent from "../floatComponent";
import InputFileComponent from "../inputFileComponent";
import InputGlobalComponent from "../inputGlobalComponent";
import InputListComponent from "../inputListComponent";
import IntComponent from "../intComponent";
import KeypairListComponent from "../keypairListComponent";
import PromptAreaComponent from "../promptComponent";
import TextAreaComponent from "../textAreaComponent";
import ToggleShadComponent from "../toggleShadComponent";
import { useState } from "react";
import useFlowStore from "../../stores/flowStore";
export default function TableNodeCellRender({
node: { data: templateData },
value: {
value: templateValue,
nodeClass,
handleOnNewValue,
handleOnChangeDb,
},
}: CustomCellRendererProps) {
console.log(
templateData,
templateValue,
nodeClass,
handleOnNewValue,
handleOnChangeDb,
);
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
const edges = useFlowStore((state) => state.edges);
const id = {
inputTypes: templateData.input_types,
type: templateData.type,
id: nodeClass.id,
fieldName: templateData.key,
};
const disabled =
edges.some(
(edge) =>
edge.targetHandle ===
scapedJSONStringfy(
templateData.proxy
? {
...id,
proxy: templateData.proxy,
}
: id,
),
) ?? false;
function getCellType() {
switch (templateData.type) {
case "str":
if (!templateData.options) {
return (
<div className="w-[300px]">
{templateData?.list ? (
<InputListComponent
componentName={templateData.key ?? undefined}
editNode={true}
disabled={disabled}
value={
!templateValue || templateValue === ""
? [""]
: templateValue
}
onChange={(value: string[]) => {
handleOnNewValue(value, templateData.key);
}}
/>
) : templateData.multiline ? (
<TextAreaComponent
id={"textarea-edit-" + templateData.name}
data-testid={"textarea-edit-" + templateData.name}
disabled={disabled}
editNode={true}
value={templateData.value ?? ""}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateData.key);
}}
/>
) : (
<InputGlobalComponent
disabled={disabled}
editNode={true}
onChange={(value) =>
handleOnNewValue(value, templateData.key)
}
setDb={(value) => {
handleOnChangeDb(value, templateData.key);
}}
name={templateData.key}
data={templateData}
/>
)}
</div>
);
} else {
return (
<div className="w-[300px]">
<Dropdown
editNode={true}
options={templateData.options}
onSelect={(value) => handleOnNewValue(value, templateData.key)}
value={templateData.value ?? "Choose an option"}
id={"dropdown-edit-" + templateData.name}
></Dropdown>
</div>
);
}
case "NestedDict":
return (
<div className=" w-full">
<DictComponent
disabled={disabled}
editNode={true}
value={templateValue.toString() === "{}" ? {} : templateValue}
onChange={(newValue) => {
templateValue = newValue;
handleOnNewValue(newValue, templateData.key);
}}
id="editnode-div-dict-input"
/>
</div>
);
break;
case "dict":
return (
<div
className={classNames(
"max-h-48 w-full overflow-auto custom-scroll",
templateValue?.length > 1 ? "my-3" : "",
)}
>
<KeypairListComponent
disabled={disabled}
editNode={true}
value={
templateData.value?.length === 0 || !templateData.value
? [{ "": "" }]
: convertObjToArray(templateValue, templateData.type)
}
duplicateKey={errorDuplicateKey}
onChange={(newValue) => {
const valueToNumbers = convertValuesToNumbers(newValue);
templateValue = valueToNumbers;
setErrorDuplicateKey(hasDuplicateKeys(valueToNumbers));
handleOnNewValue(valueToNumbers, templateData.key);
}}
isList={templateData.list ?? false}
/>
</div>
);
break;
case "bool":
return (
<div className="ml-auto">
{" "}
<ToggleShadComponent
id={"toggle-edit-" + templateData.name}
disabled={disabled}
enabled={templateData.value}
setEnabled={(isEnabled) => {
handleOnNewValue(isEnabled, templateData.key);
}}
size="small"
editNode={true}
/>
</div>
);
case "float":
return (
<div className="w-[300px]">
<FloatComponent
disabled={disabled}
editNode={true}
rangeSpec={templateData.rangeSpec}
value={templateData.value ?? ""}
onChange={(value) => {
handleOnNewValue(value, templateData.key);
}}
/>
</div>
);
case "int":
return (
<div className="w-[300px]">
<IntComponent
rangeSpec={templateData.rangeSpec}
id={"edit-int-input-" + templateData.name}
disabled={disabled}
editNode={true}
value={templateData.value ?? ""}
onChange={(value) => {
handleOnNewValue(value, templateData.key);
}}
/>
</div>
);
break;
case "file":
return (
<div className="w-[300px]">
<InputFileComponent
editNode={true}
disabled={disabled}
value={templateData.value ?? ""}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateData.key);
}}
fileTypes={templateData.fileTypes}
onFileChange={(filePath: string) => {
templateData.file_path = filePath;
}}
></InputFileComponent>
</div>
);
case "prompt":
return (
<div className="w-[300px]">
<PromptAreaComponent
readonly={nodeClass.flow ? true : false}
field_name={templateData.key}
editNode={true}
disabled={disabled}
nodeClass={nodeClass}
setNodeClass={(value) => {
nodeClass = value;
}}
value={templateValue ?? ""}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateData.key);
}}
id={"prompt-area-edit-" + templateData.name}
data-testid={"modal-prompt-input-" + templateData.name}
/>
</div>
);
break;
case "code":
return (
<div className="w-[300px]">
<CodeAreaComponent
readonly={nodeClass.flow && templateData.dynamic ? true : false}
dynamic={templateData.dynamic ?? false}
setNodeClass={(value) => {
nodeClass = value;
}}
nodeClass={nodeClass}
disabled={disabled}
editNode={true}
value={templateData.value ?? ""}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateData.key);
}}
id={"code-area-edit" + templateData.name}
/>
</div>
);
break;
case "Any":
return <>-</>;
break;
default:
return String(templateValue);
}
}
return (
<div className="group flex h-full w-full items-center align-middle">
{getCellType()}
</div>
);
}

View file

@ -1,46 +1,20 @@
import { cloneDeep } from "lodash";
import { forwardRef, useEffect, useState } from "react";
import CodeAreaComponent from "../../components/codeAreaComponent";
import DictComponent from "../../components/dictComponent";
import Dropdown from "../../components/dropdownComponent";
import FloatComponent from "../../components/floatComponent";
import 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";
import PromptAreaComponent from "../../components/promptComponent";
import ShadTooltip from "../../components/shadTooltipComponent";
import TextAreaComponent from "../../components/textAreaComponent";
import ToggleShadComponent from "../../components/toggleShadComponent";
import { Badge } from "../../components/ui/badge";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "../../components/ui/table";
import {
LANGFLOW_SUPPORTED_TYPES,
limitScrollFieldsModal,
} from "../../constants/constants";
import { Case } from "../../shared/components/caseComponent";
import useFlowStore from "../../stores/flowStore";
import { NodeDataType } from "../../types/flow";
import {
convertObjToArray,
convertValuesToNumbers,
hasDuplicateKeys,
scapedJSONStringfy,
} from "../../utils/reactflowUtils";
import { classNames } from "../../utils/utils";
import BaseModal from "../baseModal";
import TableComponent from "../../components/tableComponent";
import TableAutoCellRender from "../../components/tableAutoCellRender";
import { TemplateVariableType } from "../../types/api";
import TableNodeCellRender from "../../components/tableNodeCellRender";
import { ValueGetterParams } from "ag-grid-community";
const EditNodeModal = forwardRef(
(
@ -63,7 +37,6 @@ const EditNodeModal = forwardRef(
const [myData, setMyData] = useState(dataFromStore ?? data);
const edges = useFlowStore((state) => state.edges);
const setNode = useFlowStore((state) => state.setNode);
function changeAdvanced(n) {
@ -89,12 +62,6 @@ const EditNodeModal = forwardRef(
}
}, [open]);
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
const type = (templateParam) => {
return myData.node?.template[templateParam].type;
};
const rowData = Object.keys(myData.node!.template)
.filter((key: string) => {
const templateParam = myData.node!.template[
@ -103,7 +70,11 @@ const EditNodeModal = forwardRef(
return (
key.charAt(0) !== "_" &&
templateParam.show &&
LANGFLOW_SUPPORTED_TYPES.has(templateParam.type)
LANGFLOW_SUPPORTED_TYPES.has(templateParam.type) &&
!(
(key === "code" && templateParam.type === "code") ||
(key.includes("code") && templateParam.proxy)
)
);
})
.map((key: string) => {
@ -111,44 +82,65 @@ const EditNodeModal = forwardRef(
key
] as TemplateVariableType;
return {
param:
(templateParam.display_name
? templateParam.display_name
: templateParam.name) ?? key,
desc: templateParam.info ?? "",
value: templateParam.value ?? "",
show: !templateParam.advanced ?? "",
...templateParam,
key: key,
};
});
const columnDefs = [
{
headerName: "Parameter",
field: "param",
headerName: "Name",
field: "display_name",
valueGetter: (params) => {
const templateParam = params.data;
return (
(templateParam.display_name
? templateParam.display_name
: templateParam.name) ?? params.data.key
);
},
cellRenderer: TableAutoCellRender,
flex: 1,
resizable: false,
},
{
headerName: "Description",
field: "desc",
cellRenderer: TableAutoCellRender,
flex: 1,
resizable: false,
},
{
headerName: "Value",
field: "value",
field: "info",
cellRenderer: TableAutoCellRender,
flex: 2,
resizable: false,
},
{
headerName: "Value",
field: "value",
cellRenderer: TableNodeCellRender,
valueGetter: (params: ValueGetterParams) => {
console.log("params", params);
return {
value: params.data.value,
nodeClass: myData.node,
handleOnNewValue: handleOnNewValue,
handleOnChangeDb: (value, key) => {
setMyData((oldData) => {
let newData = cloneDeep(oldData);
newData.node!.template[key].load_from_db = value;
return newData;
});
},
};
},
minWidth: 300,
flex: 1,
resizable: false,
},
{
headerName: "Show",
field: "show",
field: "advanced",
cellRenderer: "agCheckboxCellRenderer",
cellEditor: "agCheckboxCellEditor",
valueGetter: (params) => {
return !params.data.advanced;
},
valueSetter: (params) => {
changeAdvanced(params.data.key);
return true;
@ -196,518 +188,14 @@ const EditNodeModal = forwardRef(
<span className="edit-node-modal-span">Parameters</span>
</div>
<div className="edit-node-modal-arrangement">
<div
className={classNames(
"edit-node-modal-box",
nodeLength > limitScrollFieldsModal
? "overflow-scroll overflow-x-hidden custom-scroll"
: "",
)}
>
{nodeLength > 0 && (
<div className="edit-node-modal-table">
<div className="h-32">
<TableComponent columnDefs={columnDefs} rowData={rowData} />
</div>
<Table className="table-fixed bg-muted outline-1">
<TableHeader className="edit-node-modal-table-header">
<TableRow className="">
<TableHead className="h-7 text-center">PARAM</TableHead>
<TableHead className="h-7 text-center">DESC</TableHead>
<TableHead className="h-7 p-0 text-center">
VALUE
</TableHead>
<TableHead className="h-7 text-center">SHOW</TableHead>
</TableRow>
</TableHeader>
<TableBody className="p-0">
{Object.keys(myData.node!.template)
.filter(
(templateParam) =>
templateParam.charAt(0) !== "_" &&
myData.node?.template[templateParam].show &&
LANGFLOW_SUPPORTED_TYPES.has(
myData.node!.template[templateParam].type,
),
)
.map((templateParam, index) => {
let id = {
inputTypes:
myData.node!.template[templateParam].input_types,
type: myData.node!.template[templateParam].type,
id: myData.id,
fieldName: templateParam,
};
let disabled =
edges.some(
(edge) =>
edge.targetHandle ===
scapedJSONStringfy(
myData.node!.template[templateParam].proxy
? {
...id,
proxy:
myData.node?.template[templateParam]
.proxy,
}
: id,
),
) ?? false;
return (
<TableRow
key={index}
className={
"h-10 " +
((templateParam === "code" &&
type(templateParam) === "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
styleClasses="z-50"
content={
myData.node?.template[templateParam].proxy
? myData.node?.template[templateParam]
.proxy?.id
: myData.node?.template[templateParam]
.display_name
? myData.node!.template[templateParam]
.display_name
: myData.node?.template[templateParam]
.name
}
>
<span>
{myData.node?.template[templateParam]
.display_name
? myData.node!.template[templateParam]
.display_name
: myData.node?.template[templateParam]
.name}
</span>
</ShadTooltip>
</TableCell>
<TableCell className="truncate p-0 text-center text-sm text-foreground sm:px-3">
<ShadTooltip
styleClasses="z-50"
content={
data.node?.template[templateParam]?.info ??
null
}
>
<span>
{data.node?.template[templateParam]?.info ??
""}
</span>
</ShadTooltip>
</TableCell>
<TableCell className="w-[300px] p-0 text-center text-xs text-foreground ">
<Case
condition={
type(templateParam) === "str" &&
!myData.node!.template[templateParam]
.options
}
>
<div className="mx-auto">
{myData.node!.template[templateParam]
?.list ? (
<InputListComponent
componentName={templateParam}
editNode={true}
disabled={disabled}
value={
!myData.node!.template[templateParam]
.value ||
myData.node!.template[templateParam]
.value === ""
? [""]
: myData.node!.template[
templateParam
].value
}
onChange={(value: string[]) => {
handleOnNewValue(
value,
templateParam,
);
}}
/>
) : myData.node!.template[templateParam]
.multiline ? (
<TextAreaComponent
id={
"textarea-edit-" +
myData.node!.template[templateParam]
.name
}
data-testid={
"textarea-edit-" +
myData.node!.template[templateParam]
.name
}
disabled={disabled}
editNode={true}
value={
myData.node!.template[templateParam]
.value ?? ""
}
onChange={(
value: string | string[],
) => {
handleOnNewValue(
value,
templateParam,
);
}}
/>
) : (
<InputGlobalComponent
disabled={disabled}
editNode={true}
onChange={(value) =>
handleOnNewValue(value, templateParam)
}
setDb={(value) => {
setMyData((oldData) => {
let newData = cloneDeep(oldData);
newData.node!.template[
templateParam
].load_from_db = value;
return newData;
});
}}
name={templateParam}
data={myData}
/>
)}
</div>
</Case>
<Case
condition={
type(templateParam) === "NestedDict"
}
>
<div className=" w-full">
<DictComponent
disabled={disabled}
editNode={true}
value={
myData.node!.template[
templateParam
]?.value?.toString() === "{}"
? {}
: myData.node!.template[templateParam]
.value
}
onChange={(newValue) => {
myData.node!.template[
templateParam
].value = newValue;
handleOnNewValue(
newValue,
templateParam,
);
}}
id="editnode-div-dict-input"
/>
</div>
</Case>
<Case
condition={type(templateParam) === "dict"}
>
<div
className={classNames(
"max-h-48 w-full overflow-auto custom-scroll",
myData.node!.template[templateParam].value
?.length > 1
? "my-3"
: "",
)}
>
<KeypairListComponent
disabled={disabled}
editNode={true}
value={
myData.node!.template[templateParam]
.value?.length === 0 ||
!myData.node!.template[templateParam]
.value
? [{ "": "" }]
: convertObjToArray(
myData.node!.template[
templateParam
].value,
type(templateParam)!,
)
}
duplicateKey={errorDuplicateKey}
onChange={(newValue) => {
const valueToNumbers =
convertValuesToNumbers(newValue);
myData.node!.template[
templateParam
].value = valueToNumbers;
setErrorDuplicateKey(
hasDuplicateKeys(valueToNumbers),
);
handleOnNewValue(
valueToNumbers,
templateParam,
);
}}
isList={
data.node?.template[templateParam]
?.list ?? false
}
/>
</div>
</Case>
<Case
condition={type(templateParam) === "bool"}
>
<div className="ml-auto">
{" "}
<ToggleShadComponent
id={
"toggle-edit-" +
myData.node!.template[templateParam]
.name
}
disabled={disabled}
enabled={
myData.node!.template[templateParam]
.value
}
setEnabled={(isEnabled) => {
handleOnNewValue(
isEnabled,
templateParam,
);
}}
size="small"
editNode={true}
/>
</div>
</Case>
<Case
condition={type(templateParam) === "float"}
>
<div className="mx-auto">
<FloatComponent
disabled={disabled}
editNode={true}
rangeSpec={
myData.node!.template[templateParam]
.rangeSpec
}
value={
myData.node!.template[templateParam]
.value ?? ""
}
onChange={(value) => {
handleOnNewValue(value, templateParam);
}}
/>
</div>
</Case>
<Case
condition={
type(templateParam) === "str" &&
myData.node!.template[templateParam].options
}
>
<div className="mx-auto">
<Dropdown
editNode={true}
options={
myData.node!.template[templateParam]
.options
}
onSelect={(value) =>
handleOnNewValue(value, templateParam)
}
value={
myData.node!.template[templateParam]
.value ?? "Choose an option"
}
id={
"dropdown-edit-" +
myData.node!.template[templateParam]
.name
}
></Dropdown>
</div>
</Case>
<Case condition={type(templateParam) === "int"}>
<div className="mx-auto">
<IntComponent
rangeSpec={
data.node?.template[templateParam]
?.rangeSpec
}
id={
"edit-int-input-" +
myData.node!.template[templateParam]
.name
}
disabled={disabled}
editNode={true}
value={
myData.node!.template[templateParam]
.value ?? ""
}
onChange={(value) => {
handleOnNewValue(value, templateParam);
}}
/>
</div>
</Case>
<Case
condition={type(templateParam) === "file"}
>
<div className="mx-auto">
<InputFileComponent
editNode={true}
disabled={disabled}
value={
myData.node!.template[templateParam]
.value ?? ""
}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateParam);
}}
fileTypes={
myData.node!.template[templateParam]
.fileTypes
}
onFileChange={(filePath: string) => {
data.node!.template[
templateParam
].file_path = filePath;
}}
></InputFileComponent>
</div>
</Case>
<Case
condition={type(templateParam) === "prompt"}
>
<div className="mx-auto">
<PromptAreaComponent
readonly={
myData.node?.flow ? true : false
}
field_name={templateParam}
editNode={true}
disabled={disabled}
nodeClass={myData.node}
setNodeClass={(nodeClass) => {
myData.node = nodeClass;
}}
value={
myData.node!.template[templateParam]
.value ?? ""
}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateParam);
}}
id={
"prompt-area-edit-" +
myData.node!.template[templateParam]
.name
}
data-testid={
"modal-prompt-input-" +
myData.node!.template[templateParam]
.name
}
/>
</div>
</Case>
<Case
condition={type(templateParam) === "code"}
>
<div className="mx-auto">
<CodeAreaComponent
readonly={
myData.node?.flow &&
myData.node!.template[templateParam]
.dynamic
? true
: false
}
dynamic={
data.node!.template[templateParam]
?.dynamic ?? false
}
setNodeClass={(nodeClass) => {
data.node = nodeClass;
}}
nodeClass={data.node}
disabled={disabled}
editNode={true}
value={
myData.node!.template[templateParam]
.value ?? ""
}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateParam);
}}
id={
"code-area-edit" +
myData.node!.template[templateParam]
.name
}
/>
</div>
</Case>
<Case condition={type(templateParam) === "Any"}>
<>-</>
</Case>
</TableCell>
<TableCell className="p-0 text-right">
<div className="items-center text-center">
<ToggleShadComponent
id={
"show" +
myData.node?.template[templateParam].name
}
enabled={
!myData.node?.template[templateParam]
.advanced
}
setEnabled={(e) => {
changeAdvanced(templateParam);
}}
disabled={disabled}
size="small"
editNode={true}
/>
</div>
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
<div className="w-full">
{nodeLength > 0 && (
<div className="edit-node-modal-table">
<div className="h-96">
<TableComponent columnDefs={columnDefs} rowData={rowData} />
</div>
)}
</div>
</div>
)}
</div>
</BaseModal.Content>