Fix workflow fields not updating correctly (#810)

This commit is contained in:
Kerem Yilmaz
2024-09-11 08:55:51 -07:00
committed by GitHub
parent 2b365bce59
commit dddfaf98e2
8 changed files with 151 additions and 91 deletions

View File

@@ -6,10 +6,15 @@ import { Handle, NodeProps, Position, useReactFlow } from "@xyflow/react";
import { EditableNodeTitle } from "../components/EditableNodeTitle";
import { NodeActionMenu } from "../NodeActionMenu";
import type { CodeBlockNode } from "./types";
import { useState } from "react";
function CodeBlockNode({ id, data }: NodeProps<CodeBlockNode>) {
const { updateNodeData } = useReactFlow();
const deleteNodeCallback = useDeleteNodeCallback();
const [label, setLabel] = useState(data.label);
const [inputs, setInputs] = useState({
code: data.code,
});
return (
<div>
@@ -33,9 +38,12 @@ function CodeBlockNode({ id, data }: NodeProps<CodeBlockNode>) {
</div>
<div className="flex flex-col gap-1">
<EditableNodeTitle
value={data.label}
value={label}
editable={data.editable}
onChange={(value) => updateNodeData(id, { label: value })}
onChange={(value) => {
setLabel(value);
updateNodeData(id, { label: value });
}}
/>
<span className="text-xs text-slate-400">Code Block</span>
</div>
@@ -50,11 +58,12 @@ function CodeBlockNode({ id, data }: NodeProps<CodeBlockNode>) {
<Label className="text-xs text-slate-300">Code Input</Label>
<CodeEditor
language="python"
value={data.code}
value={inputs.code}
onChange={(value) => {
if (!data.editable) {
return;
}
setInputs({ ...inputs, code: value });
updateNodeData(id, { code: value });
}}
className="nopan"

View File

@@ -49,16 +49,7 @@ function DownloadNode({ id, data }: NodeProps<DownloadNode>) {
<div className="space-y-4">
<div className="space-y-1">
<Label className="text-sm text-slate-400">File URL</Label>
<Input
value={data.url}
onChange={(event) => {
if (!data.editable) {
return;
}
updateNodeData(id, { url: event.target.value });
}}
className="nopan"
/>
<Input value={data.url} disabled className="nopan" />
</div>
</div>
</div>

View File

@@ -5,10 +5,15 @@ import { Handle, NodeProps, Position, useReactFlow } from "@xyflow/react";
import { EditableNodeTitle } from "../components/EditableNodeTitle";
import { NodeActionMenu } from "../NodeActionMenu";
import type { FileParserNode } from "./types";
import { useState } from "react";
function FileParserNode({ id, data }: NodeProps<FileParserNode>) {
const { updateNodeData } = useReactFlow();
const deleteNodeCallback = useDeleteNodeCallback();
const [label, setLabel] = useState(data.label);
const [inputs, setInputs] = useState({
fileUrl: data.fileUrl,
});
return (
<div>
@@ -32,9 +37,12 @@ function FileParserNode({ id, data }: NodeProps<FileParserNode>) {
</div>
<div className="flex flex-col gap-1">
<EditableNodeTitle
value={data.label}
value={label}
editable={data.editable}
onChange={(value) => updateNodeData(id, { label: value })}
onChange={(value) => {
setLabel(value);
updateNodeData(id, { label: value });
}}
/>
<span className="text-xs text-slate-400">File Parser Block</span>
</div>
@@ -49,11 +57,12 @@ function FileParserNode({ id, data }: NodeProps<FileParserNode>) {
<div className="space-y-1">
<span className="text-sm text-slate-400">File URL</span>
<Input
value={data.fileUrl}
value={inputs.fileUrl}
onChange={(event) => {
if (!data.editable) {
return;
}
setInputs({ ...inputs, fileUrl: event.target.value });
updateNodeData(id, { fileUrl: event.target.value });
}}
className="nopan"

View File

@@ -13,11 +13,16 @@ import {
import { EditableNodeTitle } from "../components/EditableNodeTitle";
import { NodeActionMenu } from "../NodeActionMenu";
import type { LoopNode } from "./types";
import { useState } from "react";
function LoopNode({ id, data }: NodeProps<LoopNode>) {
const { updateNodeData } = useReactFlow();
const nodes = useNodes();
const deleteNodeCallback = useDeleteNodeCallback();
const [label, setLabel] = useState(data.label);
const [inputs, setInputs] = useState({
loopValue: data.loopValue,
});
const children = nodes.filter((node) => node.parentId === id);
const furthestDownChild: Node | null = children.reduce(
@@ -67,9 +72,12 @@ function LoopNode({ id, data }: NodeProps<LoopNode>) {
</div>
<div className="flex flex-col gap-1">
<EditableNodeTitle
value={data.label}
value={label}
editable={data.editable}
onChange={(value) => updateNodeData(id, { label: value })}
onChange={(value) => {
setLabel(value);
updateNodeData(id, { label: value });
}}
/>
<span className="text-xs text-slate-400">Loop Block</span>
</div>
@@ -83,11 +91,12 @@ function LoopNode({ id, data }: NodeProps<LoopNode>) {
<div className="space-y-1">
<Label className="text-xs text-slate-300">Loop Value</Label>
<Input
value={data.loopValue}
value={inputs.loopValue}
onChange={(event) => {
if (!data.editable) {
return;
}
setInputs({ ...inputs, loopValue: event.target.value });
updateNodeData(id, { loopValue: event.target.value });
}}
placeholder="What value are you iterating over?"

View File

@@ -7,10 +7,27 @@ import { Handle, NodeProps, Position, useReactFlow } from "@xyflow/react";
import { EditableNodeTitle } from "../components/EditableNodeTitle";
import { NodeActionMenu } from "../NodeActionMenu";
import type { SendEmailNode } from "./types";
import { useState } from "react";
function SendEmailNode({ id, data }: NodeProps<SendEmailNode>) {
const { updateNodeData } = useReactFlow();
const deleteNodeCallback = useDeleteNodeCallback();
const [label, setLabel] = useState(data.label);
const [inputs, setInputs] = useState({
sender: data.sender,
recipients: data.recipients,
subject: data.subject,
body: data.body,
fileAttachments: data.fileAttachments,
});
function handleChange(key: string, value: unknown) {
if (!data.editable) {
return;
}
setInputs({ ...inputs, [key]: value });
updateNodeData(id, { [key]: value });
}
return (
<div>
@@ -34,9 +51,12 @@ function SendEmailNode({ id, data }: NodeProps<SendEmailNode>) {
</div>
<div className="flex flex-col gap-1">
<EditableNodeTitle
value={data.label}
value={label}
editable={data.editable}
onChange={(value) => updateNodeData(id, { label: value })}
onChange={(value) => {
setLabel(value);
updateNodeData(id, { label: value });
}}
/>
<span className="text-xs text-slate-400">Send Email Block</span>
</div>
@@ -54,9 +74,9 @@ function SendEmailNode({ id, data }: NodeProps<SendEmailNode>) {
if (!data.editable) {
return;
}
updateNodeData(id, { sender: event.target.value });
handleChange("sender", event.target.value);
}}
value={data.sender}
value={inputs.sender}
placeholder="example@gmail.com"
className="nopan"
/>
@@ -68,9 +88,9 @@ function SendEmailNode({ id, data }: NodeProps<SendEmailNode>) {
if (!data.editable) {
return;
}
updateNodeData(id, { recipients: event.target.value });
handleChange("recipients", event.target.value);
}}
value={data.recipients}
value={inputs.recipients}
placeholder="example@gmail.com, example2@gmail.com..."
className="nopan"
/>
@@ -83,9 +103,9 @@ function SendEmailNode({ id, data }: NodeProps<SendEmailNode>) {
if (!data.editable) {
return;
}
updateNodeData(id, { subject: event.target.value });
handleChange("subject", event.target.value);
}}
value={data.subject}
value={inputs.subject}
placeholder="What is the gist?"
className="nopan"
/>
@@ -97,9 +117,9 @@ function SendEmailNode({ id, data }: NodeProps<SendEmailNode>) {
if (!data.editable) {
return;
}
updateNodeData(id, { body: event.target.value });
handleChange("body", event.target.value);
}}
value={data.body}
value={inputs.body}
placeholder="What would you like to say?"
className="nopan"
/>
@@ -108,12 +128,12 @@ function SendEmailNode({ id, data }: NodeProps<SendEmailNode>) {
<div className="space-y-1">
<Label className="text-xs text-slate-300">File Attachments</Label>
<Input
value={data.fileAttachments}
value={inputs.fileAttachments}
onChange={(event) => {
if (!data.editable) {
return;
}
updateNodeData(id, { fileAttachments: event.target.value });
handleChange("fileAttachments", event.target.value);
}}
className="nopan"
/>

View File

@@ -32,19 +32,41 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
const { editable } = data;
const deleteNodeCallback = useDeleteNodeCallback();
const [label, setLabel] = useState(data.label);
const [inputs, setInputs] = useState({
url: data.url,
navigationGoal: data.navigationGoal,
dataExtractionGoal: data.dataExtractionGoal,
dataSchema: data.dataSchema,
maxRetries: data.maxRetries,
maxStepsOverride: data.maxStepsOverride,
allowDownloads: data.allowDownloads,
errorCodeMapping: data.errorCodeMapping,
totpVerificationUrl: data.totpVerificationUrl,
totpIdentifier: data.totpIdentifier,
});
function handleChange(key: string, value: unknown) {
if (!editable) {
return;
}
setInputs({ ...inputs, [key]: value });
updateNodeData(id, { [key]: value });
}
const basicContent = (
<>
<div className="space-y-1">
<Label className="text-xs text-slate-300">URL</Label>
<AutoResizingTextarea
value={data.url}
value={inputs.url}
className="nopan"
name="url"
onChange={(event) => {
if (!editable) {
return;
}
updateNodeData(id, { url: event.target.value });
handleChange("url", event.target.value);
}}
placeholder="https://"
/>
@@ -56,9 +78,9 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
if (!editable) {
return;
}
updateNodeData(id, { navigationGoal: event.target.value });
handleChange("navigationGoal", event.target.value);
}}
value={data.navigationGoal}
value={inputs.navigationGoal}
placeholder="What are you looking to do?"
className="nopan"
/>
@@ -83,9 +105,9 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
if (!editable) {
return;
}
updateNodeData(id, { url: event.target.value });
handleChange("url", event.target.value);
}}
value={data.url}
value={inputs.url}
placeholder="https://"
className="nopan"
/>
@@ -97,9 +119,9 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
if (!editable) {
return;
}
updateNodeData(id, { navigationGoal: event.target.value });
handleChange("navigationGoal", event.target.value);
}}
value={data.navigationGoal}
value={inputs.navigationGoal}
placeholder="What are you looking to do?"
className="nopan"
/>
@@ -120,11 +142,9 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
if (!editable) {
return;
}
updateNodeData(id, {
dataExtractionGoal: event.target.value,
});
handleChange("dataExtractionGoal", event.target.value);
}}
value={data.dataExtractionGoal}
value={inputs.dataExtractionGoal}
placeholder="What outputs are you looking to get?"
className="nopan"
/>
@@ -133,27 +153,25 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
<div className="flex gap-2">
<Label className="text-xs text-slate-300">Data Schema</Label>
<Checkbox
checked={data.dataSchema !== "null"}
checked={inputs.dataSchema !== "null"}
onCheckedChange={(checked) => {
if (!editable) {
return;
}
updateNodeData(id, {
dataSchema: checked ? "{}" : "null",
});
handleChange("dataSchema", checked ? "{}" : "null");
}}
/>
</div>
{data.dataSchema !== "null" && (
{inputs.dataSchema !== "null" && (
<div>
<CodeEditor
language="json"
value={data.dataSchema}
value={inputs.dataSchema}
onChange={(value) => {
if (!editable) {
return;
}
updateNodeData(id, { dataSchema: value });
handleChange("dataSchema", value);
}}
className="nowheel nopan"
/>
@@ -176,14 +194,12 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
placeholder="0"
className="nopan w-44"
min="0"
value={data.maxRetries ?? 0}
value={inputs.maxRetries ?? 0}
onChange={(event) => {
if (!editable) {
return;
}
updateNodeData(id, {
maxRetries: Number(event.target.value),
});
handleChange("maxRetries", Number(event.target.value));
}}
/>
</div>
@@ -196,14 +212,15 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
placeholder="0"
className="nopan w-44"
min="0"
value={data.maxStepsOverride ?? 0}
value={inputs.maxStepsOverride ?? 0}
onChange={(event) => {
if (!editable) {
return;
}
updateNodeData(id, {
maxStepsOverride: Number(event.target.value),
});
handleChange(
"maxStepsOverride",
Number(event.target.value),
);
}}
/>
</div>
@@ -213,12 +230,12 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
</Label>
<div className="w-44">
<Switch
checked={data.allowDownloads}
checked={inputs.allowDownloads}
onCheckedChange={(checked) => {
if (!editable) {
return;
}
updateNodeData(id, { allowDownloads: checked });
handleChange("allowDownloads", checked);
}}
/>
</div>
@@ -229,28 +246,26 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
Error Messages
</Label>
<Checkbox
checked={data.errorCodeMapping !== "null"}
checked={inputs.errorCodeMapping !== "null"}
disabled={!editable}
onCheckedChange={(checked) => {
if (!editable) {
return;
}
updateNodeData(id, {
errorCodeMapping: checked ? "{}" : "null",
});
handleChange("errorCodeMapping", checked ? "{}" : "null");
}}
/>
</div>
{data.errorCodeMapping !== "null" && (
{inputs.errorCodeMapping !== "null" && (
<div>
<CodeEditor
language="json"
value={data.errorCodeMapping}
value={inputs.errorCodeMapping}
onChange={(value) => {
if (!editable) {
return;
}
updateNodeData(id, { errorCodeMapping: value });
handleChange("errorCodeMapping", value);
}}
className="nowheel nopan"
/>
@@ -273,11 +288,9 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
if (!editable) {
return;
}
updateNodeData(id, {
totpVerificationUrl: event.target.value,
});
handleChange("totpVerificationUrl", event.target.value);
}}
value={data.totpVerificationUrl ?? ""}
value={inputs.totpVerificationUrl ?? ""}
placeholder="https://"
className="nopan"
/>
@@ -291,9 +304,9 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
if (!editable) {
return;
}
updateNodeData(id, { totpIdentifier: event.target.value });
handleChange("totpIdentifier", event.target.value);
}}
value={data.totpIdentifier ?? ""}
value={inputs.totpIdentifier ?? ""}
placeholder="Identifier"
className="nopan"
/>
@@ -327,9 +340,12 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
</div>
<div className="flex flex-col gap-1">
<EditableNodeTitle
value={data.label}
value={label}
editable={editable}
onChange={(value) => updateNodeData(id, { label: value })}
onChange={(value) => {
setLabel(value);
updateNodeData(id, { label: value });
}}
/>
<span className="text-xs text-slate-400">Task Block</span>
</div>

View File

@@ -9,11 +9,17 @@ import { Handle, NodeProps, Position, useReactFlow } from "@xyflow/react";
import { EditableNodeTitle } from "../components/EditableNodeTitle";
import { NodeActionMenu } from "../NodeActionMenu";
import type { TextPromptNode } from "./types";
import { useState } from "react";
function TextPromptNode({ id, data }: NodeProps<TextPromptNode>) {
const { updateNodeData } = useReactFlow();
const { editable } = data;
const deleteNodeCallback = useDeleteNodeCallback();
const [label, setLabel] = useState(data.label);
const [inputs, setInputs] = useState({
prompt: data.prompt,
jsonSchema: data.jsonSchema,
});
return (
<div>
@@ -37,9 +43,12 @@ function TextPromptNode({ id, data }: NodeProps<TextPromptNode>) {
</div>
<div className="flex flex-col gap-1">
<EditableNodeTitle
value={data.label}
value={label}
editable={editable}
onChange={(value) => updateNodeData(id, { label: value })}
onChange={(value) => {
setLabel(value);
updateNodeData(id, { label: value });
}}
/>
<span className="text-xs text-slate-400">Text Prompt Block</span>
</div>
@@ -57,9 +66,10 @@ function TextPromptNode({ id, data }: NodeProps<TextPromptNode>) {
if (!editable) {
return;
}
setInputs({ ...inputs, prompt: event.target.value });
updateNodeData(id, { prompt: event.target.value });
}}
value={data.prompt}
value={inputs.prompt}
placeholder="What do you want to generate?"
className="nopan"
/>
@@ -69,26 +79,31 @@ function TextPromptNode({ id, data }: NodeProps<TextPromptNode>) {
<div className="flex gap-2">
<Label className="text-xs text-slate-300">Data Schema</Label>
<Checkbox
checked={data.jsonSchema !== "null"}
checked={inputs.jsonSchema !== "null"}
onCheckedChange={(checked) => {
if (!editable) {
return;
}
setInputs({
...inputs,
jsonSchema: checked ? "{}" : "null",
});
updateNodeData(id, {
jsonSchema: checked ? "{}" : "null",
});
}}
/>
</div>
{data.jsonSchema !== "null" && (
{inputs.jsonSchema !== "null" && (
<div>
<CodeEditor
language="json"
value={data.jsonSchema}
value={inputs.jsonSchema}
onChange={(value) => {
if (!editable) {
return;
}
setInputs({ ...inputs, jsonSchema: value });
updateNodeData(id, { jsonSchema: value });
}}
className="nowheel nopan"

View File

@@ -49,16 +49,7 @@ function UploadNode({ id, data }: NodeProps<UploadNode>) {
<div className="space-y-4">
<div className="space-y-1">
<Label className="text-sm text-slate-400">File Path</Label>
<Input
value={data.path}
onChange={(event) => {
if (!data.editable) {
return;
}
updateNodeData(id, { path: event.target.value });
}}
className="nopan"
/>
<Input value={data.path} className="nopan" disabled />
</div>
</div>
</div>