diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/BuilderActions/BuilderActions.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/BuilderActions/BuilderActions.tsx new file mode 100644 index 0000000000..88fdceb686 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/BuilderActions/BuilderActions.tsx @@ -0,0 +1,11 @@ +import { RunGraph } from "./components/RunGraph"; + +export const BuilderActions = () => { + return ( +
+ {/* TODO: Add Agent Output */} + + {/* TODO: Add Schedule run button */} +
+ ); +}; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/BuilderActions/components/RunGraph.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/BuilderActions/components/RunGraph.tsx new file mode 100644 index 0000000000..e1b56bc347 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/BuilderActions/components/RunGraph.tsx @@ -0,0 +1,32 @@ +import { Button } from "@/components/atoms/Button/Button"; +import { PlayIcon } from "lucide-react"; +import { useRunGraph } from "./useRunGraph"; +import { useGraphStore } from "@/app/(platform)/build/stores/graphStore"; +import { useShallow } from "zustand/react/shallow"; +import { StopIcon } from "@phosphor-icons/react"; +import { cn } from "@/lib/utils"; + +export const RunGraph = () => { + const { runGraph, isSaving } = useRunGraph(); + const isGraphRunning = useGraphStore( + useShallow((state) => state.isGraphRunning), + ); + + return ( + + ); +}; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/BuilderActions/components/useRunGraph.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/BuilderActions/components/useRunGraph.ts new file mode 100644 index 0000000000..717628db77 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/BuilderActions/components/useRunGraph.ts @@ -0,0 +1,62 @@ +import { usePostV1ExecuteGraphAgent } from "@/app/api/__generated__/endpoints/graphs/graphs"; +import { useNewSaveControl } from "../../../NewControlPanel/NewSaveControl/useNewSaveControl"; +import { useToast } from "@/components/molecules/Toast/use-toast"; +import { parseAsInteger, parseAsString, useQueryStates } from "nuqs"; +import { GraphExecutionMeta } from "@/app/(platform)/library/agents/[id]/components/OldAgentLibraryView/use-agent-runs"; +import { useGraphStore } from "@/app/(platform)/build/stores/graphStore"; +import { useShallow } from "zustand/react/shallow"; + +export const useRunGraph = () => { + const { onSubmit: onSaveGraph, isLoading: isSaving } = useNewSaveControl({ + showToast: false, + }); + const { toast } = useToast(); + const setIsGraphRunning = useGraphStore( + useShallow((state) => state.setIsGraphRunning), + ); + const [{ flowID, flowVersion }, setQueryStates] = useQueryStates({ + flowID: parseAsString, + flowVersion: parseAsInteger, + flowExecutionID: parseAsString, + }); + + const { mutateAsync: executeGraph } = usePostV1ExecuteGraphAgent({ + mutation: { + onSuccess: (response) => { + const { id } = response.data as GraphExecutionMeta; + setQueryStates({ + flowExecutionID: id, + }); + }, + onError: (error) => { + setIsGraphRunning(false); + + toast({ + title: (error.detail as string) ?? "An unexpected error occurred.", + description: "An unexpected error occurred.", + variant: "destructive", + }); + }, + }, + }); + + const runGraph = async () => { + setIsGraphRunning(true); + await onSaveGraph(undefined); + + // Todo : We need to save graph which has inputs and credentials inputs + await executeGraph({ + graphId: flowID ?? "", + graphVersion: flowVersion || null, + data: { + inputs: {}, + credentials_inputs: {}, + }, + }); + }; + + return { + runGraph, + isSaving, + }; +}; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/Flow.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/Flow.tsx index fc865d309a..caa049bd9e 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/Flow.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/Flow.tsx @@ -7,7 +7,11 @@ import { useNodeStore } from "../../../stores/nodeStore"; import { useMemo } from "react"; import { CustomNode } from "../nodes/CustomNode/CustomNode"; import { useCustomEdge } from "../edges/useCustomEdge"; -import { GraphLoadingBox } from "./GraphLoadingBox"; +import { useFlowRealtime } from "./useFlowRealtime"; +import { GraphLoadingBox } from "./components/GraphLoadingBox"; +import { BuilderActions } from "../BuilderActions/BuilderActions"; +import { RunningBackground } from "./components/RunningBackground"; +import { useGraphStore } from "../../../stores/graphStore"; export const Flow = () => { const nodes = useNodeStore(useShallow((state) => state.nodes)); @@ -18,8 +22,11 @@ export const Flow = () => { const { edges, onConnect, onEdgesChange } = useCustomEdge(); // We use this hook to load the graph and convert them into custom nodes and edges. - const { isFlowContentLoading } = useFlow(); + useFlow(); + useFlowRealtime(); + const { isFlowContentLoading } = useFlow(); + const { isGraphRunning } = useGraphStore(); return (
@@ -37,7 +44,9 @@ export const Flow = () => { + {isFlowContentLoading && } + {isGraphRunning && }
diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/GraphLoadingBox.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/components/GraphLoadingBox.tsx similarity index 87% rename from autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/GraphLoadingBox.tsx rename to autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/components/GraphLoadingBox.tsx index 2d11d64a51..18198f88d7 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/GraphLoadingBox.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/components/GraphLoadingBox.tsx @@ -5,7 +5,7 @@ export const GraphLoadingBox = () => {
-
+
Loading Flow diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/components/RunningBackground.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/components/RunningBackground.tsx new file mode 100644 index 0000000000..720bda48ca --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/components/RunningBackground.tsx @@ -0,0 +1,157 @@ +export const RunningBackground = () => { + return ( +
+ +
+
+
+
+
+ ); +}; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/useFlow.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/useFlow.ts index 4d1a8f3d92..9696e7777c 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/useFlow.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/useFlow.ts @@ -1,5 +1,8 @@ import { useGetV2GetSpecificBlocks } from "@/app/api/__generated__/endpoints/default/default"; -import { useGetV1GetSpecificGraph } from "@/app/api/__generated__/endpoints/graphs/graphs"; +import { + useGetV1GetExecutionDetails, + useGetV1GetSpecificGraph, +} from "@/app/api/__generated__/endpoints/graphs/graphs"; import { BlockInfo } from "@/app/api/__generated__/models/blockInfo"; import { GraphModel } from "@/app/api/__generated__/models/graphModel"; import { parseAsInteger, parseAsString, useQueryStates } from "nuqs"; @@ -8,16 +11,39 @@ import { useShallow } from "zustand/react/shallow"; import { useEffect, useMemo } from "react"; import { convertNodesPlusBlockInfoIntoCustomNodes } from "../../helper"; import { useEdgeStore } from "../../../stores/edgeStore"; +import { GetV1GetExecutionDetails200 } from "@/app/api/__generated__/models/getV1GetExecutionDetails200"; +import { useGraphStore } from "../../../stores/graphStore"; +import { AgentExecutionStatus } from "@/app/api/__generated__/models/agentExecutionStatus"; export const useFlow = () => { const addNodes = useNodeStore(useShallow((state) => state.addNodes)); const addLinks = useEdgeStore(useShallow((state) => state.addLinks)); - - const [{ flowID, flowVersion }] = useQueryStates({ + const updateNodeStatus = useNodeStore( + useShallow((state) => state.updateNodeStatus), + ); + const updateNodeExecutionResult = useNodeStore( + useShallow((state) => state.updateNodeExecutionResult), + ); + const setIsGraphRunning = useGraphStore( + useShallow((state) => state.setIsGraphRunning), + ); + const [{ flowID, flowVersion, flowExecutionID }] = useQueryStates({ flowID: parseAsString, flowVersion: parseAsInteger, + flowExecutionID: parseAsString, }); + const { data: executionDetails } = useGetV1GetExecutionDetails( + flowID || "", + flowExecutionID || "", + { + query: { + select: (res) => res.data as GetV1GetExecutionDetails200, + enabled: !!flowID && !!flowExecutionID, + }, + }, + ); + const { data: graph, isLoading: isGraphLoading } = useGetV1GetSpecificGraph( flowID ?? "", flowVersion !== null ? { version: flowVersion } : {}, @@ -57,21 +83,52 @@ export const useFlow = () => { }, [nodes, blocks]); useEffect(() => { + // adding nodes if (customNodes.length > 0) { useNodeStore.getState().setNodes([]); addNodes(customNodes); } + // adding links if (graph?.links) { useEdgeStore.getState().setConnections([]); addLinks(graph.links); } - }, [customNodes, addNodes, graph?.links]); + + // update graph running status + const isRunning = + executionDetails?.status === AgentExecutionStatus.RUNNING || + executionDetails?.status === AgentExecutionStatus.QUEUED; + setIsGraphRunning(isRunning); + + // update node execution status in nodes + if ( + executionDetails && + "node_executions" in executionDetails && + executionDetails.node_executions + ) { + executionDetails.node_executions.forEach((nodeExecution) => { + updateNodeStatus(nodeExecution.node_id, nodeExecution.status); + }); + } + + // update node execution results in nodes + if ( + executionDetails && + "node_executions" in executionDetails && + executionDetails.node_executions + ) { + executionDetails.node_executions.forEach((nodeExecution) => { + updateNodeExecutionResult(nodeExecution.node_id, nodeExecution); + }); + } + }, [customNodes, addNodes, graph?.links, executionDetails, updateNodeStatus]); useEffect(() => { return () => { useNodeStore.getState().setNodes([]); useEdgeStore.getState().setConnections([]); + setIsGraphRunning(false); }; }, []); diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/useFlowRealtime.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/useFlowRealtime.ts new file mode 100644 index 0000000000..7ab55554f5 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/useFlowRealtime.ts @@ -0,0 +1,89 @@ +// In this hook, I am only keeping websocket related code. + +import { GraphExecutionID } from "@/lib/autogpt-server-api"; +import { useBackendAPI } from "@/lib/autogpt-server-api/context"; +import { parseAsString, useQueryStates } from "nuqs"; +import { useEffect } from "react"; +import { useNodeStore } from "../../../stores/nodeStore"; +import { useShallow } from "zustand/react/shallow"; +import { NodeExecutionResult } from "@/app/api/__generated__/models/nodeExecutionResult"; +import { AgentExecutionStatus } from "@/app/api/__generated__/models/agentExecutionStatus"; +import { useGraphStore } from "../../../stores/graphStore"; + +export const useFlowRealtime = () => { + const api = useBackendAPI(); + const updateNodeExecutionResult = useNodeStore( + useShallow((state) => state.updateNodeExecutionResult), + ); + const updateStatus = useNodeStore( + useShallow((state) => state.updateNodeStatus), + ); + const setIsGraphRunning = useGraphStore( + useShallow((state) => state.setIsGraphRunning), + ); + + const [{ flowExecutionID, flowID }] = useQueryStates({ + flowExecutionID: parseAsString, + flowID: parseAsString, + }); + + useEffect(() => { + const deregisterNodeExecutionEvent = api.onWebSocketMessage( + "node_execution_event", + (data) => { + if (data.graph_exec_id != flowExecutionID) { + return; + } + // TODO: Update the states of nodes + updateNodeExecutionResult( + data.node_id, + data as unknown as NodeExecutionResult, + ); + updateStatus(data.node_id, data.status); + }, + ); + + const deregisterGraphExecutionStatusEvent = api.onWebSocketMessage( + "graph_execution_event", + (graphExecution) => { + if (graphExecution.id != flowExecutionID) { + return; + } + + const isRunning = + graphExecution.status === AgentExecutionStatus.RUNNING || + graphExecution.status === AgentExecutionStatus.QUEUED; + + setIsGraphRunning(isRunning); + }, + ); + + const deregisterGraphExecutionSubscription = + flowID && flowExecutionID + ? api.onWebSocketConnect(() => { + // Subscribe to execution updates + api + .subscribeToGraphExecution(flowExecutionID as GraphExecutionID) // TODO: We are currently using a manual type, we need to fix it in future + .then(() => { + console.debug( + `Subscribed to updates for execution #${flowExecutionID}`, + ); + }) + .catch((error) => + console.error( + `Failed to subscribe to updates for execution #${flowExecutionID}:`, + error, + ), + ); + }) + : () => {}; + + return () => { + deregisterNodeExecutionEvent(); + deregisterGraphExecutionSubscription(); + deregisterGraphExecutionStatusEvent(); + }; + }, [api, flowExecutionID]); + + return {}; +}; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/components/ObjectEditor/ObjectEditor.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/components/ObjectEditor/ObjectEditor.tsx index 6c3dd1e96c..87d593a493 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/components/ObjectEditor/ObjectEditor.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/components/ObjectEditor/ObjectEditor.tsx @@ -147,6 +147,7 @@ export const ObjectEditor = React.forwardRef( type="button" variant="secondary" size="small" + className="min-w-10" onClick={() => removeProperty(key)} disabled={disabled} > diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/CustomNode.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/CustomNode.tsx index 882c5ab039..baca71cb72 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/CustomNode.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/CustomNode.tsx @@ -6,6 +6,8 @@ import { StickyNoteBlock } from "./StickyNoteBlock"; import { BlockInfoCategoriesItem } from "@/app/api/__generated__/models/blockInfoCategoriesItem"; import { StandardNodeBlock } from "./StandardNodeBlock"; import { BlockCost } from "@/app/api/__generated__/models/blockCost"; +import { AgentExecutionStatus } from "@/app/api/__generated__/models/agentExecutionStatus"; +import { NodeExecutionResult } from "@/app/api/__generated__/models/nodeExecutionResult"; export type CustomNodeData = { hardcodedValues: { @@ -17,6 +19,8 @@ export type CustomNodeData = { outputSchema: RJSFSchema; uiType: BlockUIType; block_id: string; + status?: AgentExecutionStatus; + nodeExecutionResult?: NodeExecutionResult; // TODO : We need better type safety for the following backend fields. costs: BlockCost[]; categories: BlockInfoCategoriesItem[]; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/StandardNodeBlock.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/StandardNodeBlock.tsx index 9a33f38a68..dc7f17e5d3 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/StandardNodeBlock.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/StandardNodeBlock.tsx @@ -8,6 +8,9 @@ import { useNodeStore } from "@/app/(platform)/build/stores/nodeStore"; import { OutputHandler } from "../OutputHandler"; import { NodeCost } from "./components/NodeCost"; import { NodeBadges } from "./components/NodeBadges"; +import { NodeExecutionBadge } from "./components/NodeExecutionBadge"; +import { nodeStyleBasedOnStatus } from "./helpers"; +import { NodeDataRenderer } from "./components/NodeDataRenderer"; type StandardNodeBlockType = { data: CustomNodeData; @@ -23,57 +26,60 @@ export const StandardNodeBlock = ({ (state) => state.nodeAdvancedStates[nodeId] || false, ); const setShowAdvanced = useNodeStore((state) => state.setShowAdvanced); - + const status = useNodeStore((state) => state.getNodeStatus(nodeId)); return (
- {/* Header */} -
- {/* Upper section */} -
- - {beautifyString(data.title)} - - - #{nodeId.split("-")[0]} - +
+ {/* Header */} +
+ {/* Upper section */} +
+ + {beautifyString(data.title)} + + + #{nodeId.split("-")[0]} + +
+ {/* Lower section */} +
+ + +
- {/* Lower section */} -
- - + {/* Input Handles */} +
+
-
+ {/* Advanced Button */} +
+ + Advanced + + setShowAdvanced(nodeId, checked)} + checked={showAdvanced} + /> +
+ {/* Output Handles */} + - {/* Input Handles */} -
- +
- - {/* Advanced Button */} -
- - Advanced - - setShowAdvanced(nodeId, checked)} - checked={showAdvanced} - /> -
- - {/* Output Handles */} - + {status && }
); }; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/StickyNoteBlock.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/StickyNoteBlock.tsx index 0510ba1982..9d4eb7f4f4 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/StickyNoteBlock.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/StickyNoteBlock.tsx @@ -42,7 +42,7 @@ export const StickyNoteBlock = ({ data, id }: StickyNoteBlockType) => { style={{ transform: `rotate(${angle}deg)` }} > - Notes #{id} + Notes #{id.split("-")[0]} { const { formatCredits } = useCredits(); - const hardcodedValues = useNodeStore((state) => - state.getHardCodedValues(nodeId), + const hardcodedValues = useNodeStore( + useShallow((state) => state.getHardCodedValues(nodeId)), ); + const blockCost = blockCosts && blockCosts.find((cost) => diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeDataRenderer.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeDataRenderer.tsx new file mode 100644 index 0000000000..304d10fd13 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeDataRenderer.tsx @@ -0,0 +1,122 @@ +import { useNodeStore } from "@/app/(platform)/build/stores/nodeStore"; +import { Button } from "@/components/atoms/Button/Button"; +import { Text } from "@/components/atoms/Text/Text"; +import { beautifyString } from "@/lib/utils"; +import { + ArrowSquareInIcon, + CaretDownIcon, + CopyIcon, + InfoIcon, +} from "@phosphor-icons/react"; +import { useState } from "react"; + +import { useShallow } from "zustand/react/shallow"; + +export const NodeDataRenderer = ({ nodeId }: { nodeId: string }) => { + const [isExpanded, setIsExpanded] = useState(true); + + const nodeExecutionResult = useNodeStore( + useShallow((state) => state.getNodeExecutionResult(nodeId)), + ); + + const data = { + "[Input]": nodeExecutionResult?.input_data, + ...nodeExecutionResult?.output_data, + }; + + // Don't render if there's no data + if (!nodeExecutionResult || Object.keys(data).length === 0) { + return null; + } + + // Need to Fix - when we are on build page and try to rerun the graph again, it gives error + + return ( +
+
+ + Node Output + + +
+ + {isExpanded && ( + <> +
+ {Object.entries(data || {}).map(([key, value]) => ( +
+
+ + Pin: + + + {beautifyString(key)} + +
+
+ + Data: + +
+ + {JSON.stringify(value, null, 2)} + +
+ {/* TODO: Add tooltip for each button and also make all these blocks working */} + + + +
+
+
+
+ ))} +
+ + {/* TODO: Currently this button is not working, need to make it working */} + + + )} +
+ ); +}; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeExecutionBadge.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeExecutionBadge.tsx new file mode 100644 index 0000000000..d47ba4ea7d --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeExecutionBadge.tsx @@ -0,0 +1,32 @@ +import { AgentExecutionStatus } from "@/app/api/__generated__/models/agentExecutionStatus"; +import { Badge } from "@/components/__legacy__/ui/badge"; +import { LoadingSpinner } from "@/components/__legacy__/ui/loading"; +import { cn } from "@/lib/utils"; + +const statusStyles: Record = { + INCOMPLETE: "text-slate-700 border-slate-400", + QUEUED: "text-blue-700 border-blue-400", + RUNNING: "text-amber-700 border-amber-400", + COMPLETED: "text-green-700 border-green-400", + TERMINATED: "text-orange-700 border-orange-400", + FAILED: "text-red-700 border-red-400", +}; + +export const NodeExecutionBadge = ({ + status, +}: { + status: AgentExecutionStatus; +}) => { + return ( +
+ + {status} + {status === AgentExecutionStatus.RUNNING && ( + + )} + +
+ ); +}; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/helpers.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/helpers.ts new file mode 100644 index 0000000000..5547468828 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/helpers.ts @@ -0,0 +1,10 @@ +import { AgentExecutionStatus } from "@/app/api/__generated__/models/agentExecutionStatus"; + +export const nodeStyleBasedOnStatus: Record = { + INCOMPLETE: "ring-slate-300 bg-slate-300", + QUEUED: " ring-blue-300 bg-blue-300", + RUNNING: "ring-amber-300 bg-amber-300", + COMPLETED: "ring-green-300 bg-green-300", + TERMINATED: "ring-orange-300 bg-orange-300 ", + FAILED: "ring-red-300 bg-red-300", +}; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/OutputHandler.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/OutputHandler.tsx index 5ac148b6ab..9d99a95812 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/OutputHandler.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/OutputHandler.tsx @@ -35,7 +35,7 @@ export const OutputHandler = ({ > Output{" "} = ({ } return ( -
+
{label && schema.type && (