Make output parameters available (#825)

This commit is contained in:
Kerem Yilmaz
2024-09-12 14:47:09 -07:00
committed by GitHub
parent acd167f418
commit a5adfd3ead
4 changed files with 87 additions and 12 deletions

View File

@@ -30,6 +30,7 @@ import "./reactFlowOverrideStyles.css";
import { import {
createNode, createNode,
generateNodeLabel, generateNodeLabel,
getOutputParameterKey,
getWorkflowBlocks, getWorkflowBlocks,
layout, layout,
} from "./workflowEditorUtils"; } from "./workflowEditorUtils";
@@ -228,6 +229,7 @@ function FlowRenderer({
if (!node) { if (!node) {
return; return;
} }
const deletedNodeLabel = node.data.label;
const newNodes = nodes.filter((node) => node.id !== id); const newNodes = nodes.filter((node) => node.id !== id);
const newEdges = edges.flatMap((edge) => { const newEdges = edges.flatMap((edge) => {
if (edge.source === id) { if (edge.source === id) {
@@ -257,7 +259,24 @@ function FlowRenderer({
return; return;
} }
doLayout(newNodes, newEdges); // if any node was using the output parameter of the deleted node, remove it from their parameter keys
const newNodesWithUpdatedParameters = newNodes.map((node) => {
if (node.type === "task") {
return {
...node,
data: {
...node.data,
parameterKeys: node.data.parameterKeys.filter(
(parameter) =>
parameter !== getOutputParameterKey(deletedNodeLabel),
),
},
};
}
return node;
});
doLayout(newNodesWithUpdatedParameters, newEdges);
} }
return ( return (

View File

@@ -17,7 +17,15 @@ import {
import { Switch } from "@/components/ui/switch"; import { Switch } from "@/components/ui/switch";
import { CodeEditor } from "@/routes/workflows/components/CodeEditor"; import { CodeEditor } from "@/routes/workflows/components/CodeEditor";
import { ListBulletIcon, MixerVerticalIcon } from "@radix-ui/react-icons"; import { ListBulletIcon, MixerVerticalIcon } from "@radix-ui/react-icons";
import { Handle, NodeProps, Position, useReactFlow } from "@xyflow/react"; import {
Edge,
Handle,
NodeProps,
Position,
useEdges,
useNodes,
useReactFlow,
} from "@xyflow/react";
import { useState } from "react"; import { useState } from "react";
import { EditableNodeTitle } from "../components/EditableNodeTitle"; import { EditableNodeTitle } from "../components/EditableNodeTitle";
import { NodeActionMenu } from "../NodeActionMenu"; import { NodeActionMenu } from "../NodeActionMenu";
@@ -25,12 +33,49 @@ import { TaskNodeDisplayModeSwitch } from "./TaskNodeDisplayModeSwitch";
import { TaskNodeParametersPanel } from "./TaskNodeParametersPanel"; import { TaskNodeParametersPanel } from "./TaskNodeParametersPanel";
import type { TaskNode, TaskNodeDisplayMode } from "./types"; import type { TaskNode, TaskNodeDisplayMode } from "./types";
import { useDeleteNodeCallback } from "@/routes/workflows/hooks/useDeleteNodeCallback"; import { useDeleteNodeCallback } from "@/routes/workflows/hooks/useDeleteNodeCallback";
import { AppNode } from "..";
import { getOutputParameterKey } from "../../workflowEditorUtils";
function getPreviousNodeIds(
nodes: Array<AppNode>,
edges: Array<Edge>,
target: string,
): Array<string> {
const nodeIds: string[] = [];
const node = nodes.find((node) => node.id === target);
if (!node) {
return nodeIds;
}
let current = edges.find((edge) => edge.target === target);
if (current) {
while (current) {
nodeIds.push(current.source);
current = edges.find((edge) => edge.target === current!.source);
}
}
if (!node.parentId) {
return nodeIds;
}
return [...nodeIds, ...getPreviousNodeIds(nodes, edges, node.parentId)];
}
function TaskNode({ id, data }: NodeProps<TaskNode>) { function TaskNode({ id, data }: NodeProps<TaskNode>) {
const { updateNodeData } = useReactFlow(); const { updateNodeData } = useReactFlow();
const [displayMode, setDisplayMode] = useState<TaskNodeDisplayMode>("basic"); const [displayMode, setDisplayMode] = useState<TaskNodeDisplayMode>("basic");
const { editable } = data; const { editable } = data;
const deleteNodeCallback = useDeleteNodeCallback(); const deleteNodeCallback = useDeleteNodeCallback();
const nodes = useNodes<AppNode>();
const edges = useEdges();
const previousNodeIds = getPreviousNodeIds(nodes, edges, id);
const previousNodes = nodes.filter((node) =>
previousNodeIds.includes(node.id),
);
const labels = previousNodes
.filter((node) => node.type !== "nodeAdder")
.map((node) => node.data.label);
const outputParameterKeys = labels.map((label) =>
getOutputParameterKey(label),
);
const [label, setLabel] = useState(data.label); const [label, setLabel] = useState(data.label);
const [inputs, setInputs] = useState({ const [inputs, setInputs] = useState({
@@ -387,6 +432,7 @@ function TaskNode({ id, data }: NodeProps<TaskNode>) {
</PopoverTrigger> </PopoverTrigger>
<PopoverContent className="w-72"> <PopoverContent className="w-72">
<TaskNodeParametersPanel <TaskNodeParametersPanel
availableOutputParameters={outputParameterKeys}
parameters={data.parameterKeys} parameters={data.parameterKeys}
onParametersChange={(parameterKeys) => { onParametersChange={(parameterKeys) => {
updateNodeData(id, { parameterKeys }); updateNodeData(id, { parameterKeys });

View File

@@ -2,13 +2,20 @@ import { Checkbox } from "@/components/ui/checkbox";
import { useWorkflowParametersState } from "../../useWorkflowParametersState"; import { useWorkflowParametersState } from "../../useWorkflowParametersState";
type Props = { type Props = {
availableOutputParameters: Array<string>;
parameters: Array<string>; parameters: Array<string>;
onParametersChange: (parameters: Array<string>) => void; onParametersChange: (parameters: Array<string>) => void;
}; };
function TaskNodeParametersPanel({ parameters, onParametersChange }: Props) { function TaskNodeParametersPanel({
availableOutputParameters,
parameters,
onParametersChange,
}: Props) {
const [workflowParameters] = useWorkflowParametersState(); const [workflowParameters] = useWorkflowParametersState();
const keys = workflowParameters
.map((parameter) => parameter.key)
.concat(availableOutputParameters);
return ( return (
<div className="space-y-4"> <div className="space-y-4">
<header className="space-y-1"> <header className="space-y-1">
@@ -18,27 +25,25 @@ function TaskNodeParametersPanel({ parameters, onParametersChange }: Props) {
</span> </span>
</header> </header>
<div className="space-y-2"> <div className="space-y-2">
{workflowParameters.map((workflowParameter) => { {keys.map((key) => {
return ( return (
<div <div
key={workflowParameter.key} key={key}
className="flex items-center gap-2 rounded-sm bg-slate-elevation1 px-3 py-2" className="flex items-center gap-2 rounded-sm bg-slate-elevation1 px-3 py-2"
> >
<Checkbox <Checkbox
checked={parameters.includes(workflowParameter.key)} checked={parameters.includes(key)}
onCheckedChange={(checked) => { onCheckedChange={(checked) => {
if (checked) { if (checked) {
onParametersChange([...parameters, workflowParameter.key]); onParametersChange([...parameters, key]);
} else { } else {
onParametersChange( onParametersChange(
parameters.filter( parameters.filter((parameterKey) => parameterKey !== key),
(parameter) => parameter !== workflowParameter.key,
),
); );
} }
}} }}
/> />
<span className="text-xs">{workflowParameter.key}</span> <span className="text-xs">{key}</span>
</div> </div>
); );
})} })}

View File

@@ -616,6 +616,10 @@ function convertEchoParameters(
}); });
} }
function getOutputParameterKey(label: string) {
return label + "_output";
}
export { export {
createNode, createNode,
generateNodeData, generateNodeData,
@@ -624,4 +628,5 @@ export {
layout, layout,
generateNodeLabel, generateNodeLabel,
convertEchoParameters, convertEchoParameters,
getOutputParameterKey,
}; };