diff --git a/eng/MetaInfo.props b/eng/MetaInfo.props index 7e90fef..3b034f1 100644 --- a/eng/MetaInfo.props +++ b/eng/MetaInfo.props @@ -1,7 +1,7 @@ - 0.0.13 + 0.0.14 LittleLittleCloud git false diff --git a/stepwise-studio/components/llm-selector.tsx b/stepwise-studio/components/llm-selector.tsx index 45ef39a..1a7cb23 100644 --- a/stepwise-studio/components/llm-selector.tsx +++ b/stepwise-studio/components/llm-selector.tsx @@ -127,7 +127,9 @@ export const LLMSelector: React.FC = () => { {Array.from(availableLLMs).map((llm) => ( - {llm.name} + + {llm.name} + ))} diff --git a/stepwise-studio/components/step-node.tsx b/stepwise-studio/components/step-node.tsx index 07c890d..57f9d83 100644 --- a/stepwise-studio/components/step-node.tsx +++ b/stepwise-studio/components/step-node.tsx @@ -13,6 +13,7 @@ import { useUpdateNodeInternals, NodeResizer, NodeResizeControl, + useReactFlow, } from "reactflow"; import { Button, buttonVariants } from "./ui/button"; import { @@ -55,17 +56,10 @@ import { Switch } from "./ui/switch"; import ImageUpload from "./image-upload"; import { StepNodeStatus, ToStepNodeStatus } from "@/lib/stepRunUtils"; import { useWorkflowStore } from "@/hooks/useWorkflow"; +import { useStepRunHistoryStore } from "@/hooks/useStepRunHistory"; +import { useWorkflowEngine } from "@/hooks/useWorkflowEngine"; -export interface StepNodeProps extends StepRunDTO { - onRerunClick: (step: StepDTO) => void; - onClearClick: (step: StepDTO) => void; - onSubmitOutput: (output: VariableDTO) => void; - onCancelInput: () => void; - onResize: (height?: number, width?: number) => void; - isWorkflowRunning: boolean; - width?: number; - height?: number; -} +export interface StepNodeProps extends StepRunDTO {} const StepNodeStatusIndicator: React.FC<{ status: StepNodeStatus; @@ -167,7 +161,18 @@ const StepNodeStatusIndicator: React.FC<{ }; const StepNode: React.FC> = (prop) => { + const resetStepRunResult = useStepRunHistoryStore( + (state) => state.resetStepRunResult, + ); + const currentStepRunHistory = useStepRunHistoryStore( + (state) => state.selectedStepRunHistory, + ); + const setSelectedStepRunHistory = useStepRunHistoryStore( + (state) => state.setSelectedStepRunHistory, + ); const [step, setStep] = useState(prop.data.step!); + const executeStep = useWorkflowEngine((state) => state.executeStep); + const isWorkflowRunning = useWorkflowEngine((state) => state.isRunning); const stepNodeRef = React.useRef(null); const titleRef = React.useRef(null); const updateNodeInternals = useUpdateNodeInternals(); @@ -202,11 +207,6 @@ const StepNode: React.FC> = (prop) => { ); const [inputSwitch, setInputSwitch] = useState(false); - const [isWorkflowRunning, setIsWorkflowRunning] = useState( - prop.data.isWorkflowRunning, - ); - const [width, setWidth] = useState(prop.data.width); - const [height, setHeight] = useState(prop.data.height); const [collapseDescription, setCollapseDescription] = useState(true); @@ -223,7 +223,9 @@ const StepNode: React.FC> = (prop) => { const selectedWorkflow = useWorkflowStore( (state) => state.selectedWorkflow, ); - + const setSelectedWorkflow = useWorkflowStore( + (state) => state.setSelectedWorkflow, + ); const iconSize = 16; useEffect(() => { @@ -239,8 +241,6 @@ const StepNode: React.FC> = (prop) => { return acc; }, new Map()) ?? new Map(), ); - setWidth(prop.data.width); - setHeight(prop.data.height); setExceptionDTO(prop.data.exception); // set resize observer const resizeObserver = new ResizeObserver((entries) => { @@ -278,32 +278,26 @@ const StepNode: React.FC> = (prop) => { setStatus(ToStepNodeStatus(prop.data.status ?? "NotReady")); }, [prop.data.status]); - useEffect(() => { - setIsWorkflowRunning(prop.data.isWorkflowRunning); - }, [prop.data.isWorkflowRunning]); - useEffect(() => { setStepType( ConvertStringToStepType(prop.data.step?.step_type ?? "Ordinary"), ); }, [prop.data.step?.step_type]); - useEffect(() => { - if (prop.data.width && prop.data.height) { - setWidth(prop.data.width); - setHeight(prop.data.height); - } - }, [prop.data.width, prop.data.height]); - useEffect(() => { updateNodeInternals(prop.id); + onResize( + stepNodeRef.current?.offsetHeight!, + stepNodeRef.current?.offsetWidth!, + ); }, [ step, sourceHandleTopOffset, targetHandleTopOffsets, status, - height, - width, + stepNodeRef.current, + stepNodeRef.current?.offsetWidth, + stepNodeRef.current?.offsetHeight, ]); useEffect(() => { @@ -335,55 +329,87 @@ const StepNode: React.FC> = (prop) => { } }, [parameterRefMap.current]); - useEffect(() => { - if (stepNodeRef.current) { - if (width === undefined && stepNodeRef.current.offsetWidth) { - setWidth(stepNodeRef.current.offsetWidth); - setHeight(stepNodeRef.current.offsetHeight); - } else { - prop.data.onResize( - stepNodeRef.current.offsetHeight, - stepNodeRef.current.offsetWidth, - ); - } - } - }, [ - width, - height, - stepNodeRef.current, - stepNodeRef.current?.offsetHeight, - stepNodeRef.current?.offsetWidth, - ]); + const onClearClick = async (step: StepDTO) => { + if (!selectedWorkflow) return; + + var updatedRunSteps = resetStepRunResult( + selectedWorkflow, + step, + currentStepRunHistory, + ); + setSelectedStepRunHistory(updatedRunSteps); + }; + + const onRerunClick = async (step: StepDTO) => { + if (!selectedWorkflow) return; + executeStep(step, undefined, undefined, 1); + }; + + const onResize = async (height: number, width: number) => { + if (!selectedWorkflow) return selectedWorkflow; + console.log("Resize", height, width); + const stepNodeID = `${selectedWorkflow.name}-${step.name}`; + setSelectedWorkflow({ + ...selectedWorkflow, + stepSizes: { + ...selectedWorkflow.stepSizes, + [stepNodeID]: height && width ? { height, width } : undefined, + }, + }); + }; + + const onSubmitOutput = async (output: VariableDTO) => { + var completedStepRun = { + ...prop.data, + status: "Completed", + } as StepRunDTO; + var variable = { + status: "Variable", + result: output, + generation: output.generation, + } as StepRunDTO; + var completedRun = [ + ...currentStepRunHistory, + completedStepRun, + variable, + ]; + + setSelectedStepRunHistory(completedRun); + }; + + const onCancelInput = async () => { + var notReadyStepRun = { + ...prop.data, + status: "NotReady", + } as StepRunDTO; + + setSelectedStepRunHistory([...currentStepRunHistory, notReadyStepRun]); + }; return (
- {/* resize control */} - {height && width && stepNodeRef.current && ( + { { - if (Math.abs(param.width - width) > 10) { - setWidth(param.width); - } - }} onResizeEnd={(event, param) => { - setWidth(stepNodeRef.current!.offsetWidth); + onResize( + stepNodeRef.current!.offsetHeight, + stepNodeRef.current!.offsetWidth, + ); }} minWidth={128} - minHeight={height} - maxHeight={height} + maxWidth={512} > > = (prop) => { size={6} /> - )} + } {/* settings bar */} {/* appear when hover */}
@@ -403,7 +429,7 @@ const StepNode: React.FC> = (prop) => { variant={"outline"} size={"tinyIcon"} className="m-0 p-0" - onClick={() => prop.data.onRerunClick(step)} + onClick={() => onRerunClick(step)} > @@ -412,7 +438,7 @@ const StepNode: React.FC> = (prop) => { variant={"outline"} size={"tinyIcon"} className="m-0 p-0" - onClick={() => prop.data.onClearClick(step)} + onClick={() => onClearClick(step)} > @@ -441,7 +467,7 @@ const StepNode: React.FC> = (prop) => { />
{description && ( -
+
@@ -536,7 +562,7 @@ const StepNode: React.FC> = (prop) => { )} {output &&
} {output && ( -
+
> = (prop) => { value: inputText, generation: prop.data.generation, } as VariableDTO; - prop.data.onClearClick(step); - prop.data.onSubmitOutput(variable); + onClearClick(step); + onSubmitOutput(variable); }} > Submit @@ -613,7 +639,7 @@ const StepNode: React.FC> = (prop) => { size={"tiny"} className="text-base" onClick={() => { - prop.data.onCancelInput(); + onCancelInput(); }} > Cancel @@ -662,8 +688,8 @@ const StepNode: React.FC> = (prop) => { value: inputNumber, generation: prop.data.generation, } as VariableDTO; - prop.data.onClearClick(step); - prop.data.onSubmitOutput(variable); + onClearClick(step); + onSubmitOutput(variable); }} > Submit @@ -673,7 +699,7 @@ const StepNode: React.FC> = (prop) => { size={"tiny"} className="text-base" onClick={() => { - prop.data.onCancelInput(); + onCancelInput(); }} > Cancel @@ -722,8 +748,8 @@ const StepNode: React.FC> = (prop) => { generation: prop.data.generation, } as VariableDTO; - prop.data.onClearClick(step); - prop.data.onSubmitOutput(variable); + onClearClick(step); + onSubmitOutput(variable); }} > Submit @@ -733,7 +759,7 @@ const StepNode: React.FC> = (prop) => { size={"tiny"} className="text-base" onClick={() => { - prop.data.onCancelInput(); + onCancelInput(); }} > Cancel @@ -746,7 +772,7 @@ const StepNode: React.FC> = (prop) => { {stepType === "StepWiseUIImageInput" && status === "Queue" && ( { - prop.data.onCancelInput(); + onCancelInput(); }} onUpload={async (file) => { var variable = { @@ -757,8 +783,8 @@ const StepNode: React.FC> = (prop) => { generation: prop.data.generation, } as VariableDTO; - prop.data.onClearClick(step); - prop.data.onSubmitOutput(variable); + onClearClick(step); + onSubmitOutput(variable); }} /> )} diff --git a/stepwise-studio/components/workflow.tsx b/stepwise-studio/components/workflow.tsx index 91afd04..ad94b22 100644 --- a/stepwise-studio/components/workflow.tsx +++ b/stepwise-studio/components/workflow.tsx @@ -47,6 +47,7 @@ export type WorkflowLayout = { stepPositions: { [key: string]: { x: number; y: number } }; stepSizes: { [key: string]: { width: number; height: number } | undefined }; viewPort: Viewport; + layoutInitialized: boolean; }; export type WorkflowData = WorkflowDTO & WorkflowLayout & StepRunSidebarProps; @@ -58,7 +59,6 @@ const WorkflowInner: React.FC = (props) => { const { selectedWorkflow, updateWorkflow, setSelectedWorkflow } = useWorkflow(); const { fitView, getViewport, setViewport } = useReactFlow(); - const { maxSteps, maxParallel } = useRunSettingsStore(); const { theme } = useTheme(); const { selectedStepRunHistory, @@ -78,7 +78,6 @@ const WorkflowInner: React.FC = (props) => { const createGraphFromWorkflow = ( workflow: WorkflowData, stepRunHistory: StepRunDTO[], - isWorkflowRunning: boolean, ) => { var completedRunSteps = createLatestStepRunSnapShotFromRunHistory( workflow, @@ -97,72 +96,11 @@ const WorkflowInner: React.FC = (props) => { id: stepNodeID, type: "stepNode", position: position, - ...(size ?? { width: 200, height: 100 }), // if size is not defined, use default size style: { width: size?.width ?? "auto", height: size?.height ?? "auto", }, - data: { - ...size, - ...stepRun, - isWorkflowRunning: isWorkflowRunning, - onClearClick: (step: StepDTO) => { - if (!selectedWorkflow) return; - var updatedRunSteps = resetStepRunResult( - selectedWorkflow, - step, - stepRunHistory, - ); - setSelectedStepRunHistory(updatedRunSteps); - }, - onRerunClick: (step: StepDTO) => { - if (!selectedWorkflow) return; - executeStep(step, undefined, undefined, 1); - }, - onSubmitOutput: async (output: VariableDTO) => { - var completedStepRun = { - ...stepRun, - status: "Completed", - } as StepRunDTO; - var variable = { - status: "Variable", - result: output, - generation: output.generation, - } as StepRunDTO; - var completedRun = [ - ...stepRunHistory, - completedStepRun, - variable, - ]; - - setSelectedStepRunHistory(completedRun); - }, - onCancelInput: () => { - var notReadyStepRun = { - ...stepRun, - status: "NotReady", - } as StepRunDTO; - - setSelectedStepRunHistory([ - ...stepRunHistory, - notReadyStepRun, - ]); - }, - onResize: (height, width) => { - if (!selectedWorkflow) return selectedWorkflow; - const stepNodeID = `${workflow.name}-${step.name}`; - setSelectedWorkflow({ - ...selectedWorkflow, - stepSizes: { - ...selectedWorkflow.stepSizes, - [stepNodeID]: - height && width - ? { height, width } - : undefined, - }, - }); - }, - }, + data: stepRun, } as Node; }); @@ -216,11 +154,10 @@ const WorkflowInner: React.FC = (props) => { useEffect(() => { if (!selectedWorkflow) return; - console.log("Workflow updated", selectedWorkflow); + var graph = createGraphFromWorkflow( selectedWorkflow, selectedStepRunHistory, - isRunning, ); setNodes(graph.nodes); setEdges(graph.edges); @@ -271,8 +208,6 @@ const WorkflowInner: React.FC = (props) => { if (!selectedWorkflow) return; const { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(nodes, edges); - setNodes([...layoutedNodes]); - setEdges([...layoutedEdges]); window.requestAnimationFrame(() => { fitView(); }); @@ -288,9 +223,11 @@ const WorkflowInner: React.FC = (props) => { ); setSelectedWorkflow({ ...selectedWorkflow, + layoutInitialized: true, stepPositions: stepPositions, + viewPort: getViewport(), }); - }, [nodes, edges, setNodes, setEdges, fitView]); + }, [selectedWorkflow, nodes, edges, fitView]); return (
diff --git a/stepwise-studio/hooks/useWorkflow.tsx b/stepwise-studio/hooks/useWorkflow.tsx index 17a86d0..b2ed4d0 100644 --- a/stepwise-studio/hooks/useWorkflow.tsx +++ b/stepwise-studio/hooks/useWorkflow.tsx @@ -119,6 +119,7 @@ export const useWorkflowStore = create((set, get) => ({ }, {} as { [key: string]: { x: number; y: number } }, ), + layoutInitialized: false, } as WorkflowData); } var maps = new Map(); diff --git a/stepwise-studio/lib/utils.ts b/stepwise-studio/lib/utils.ts index 0dacee7..ba909d9 100644 --- a/stepwise-studio/lib/utils.ts +++ b/stepwise-studio/lib/utils.ts @@ -16,14 +16,14 @@ export const getLayoutedElements = ( dagreGraph.setDefaultEdgeLabel(() => ({})); dagreGraph.setGraph({ rankdir: direction }); - var maxNodeWidth = nodes.reduce( - (max, node) => Math.max(max, node.width ?? 0), - 20, - ); - var maxNodeHeight = nodes.reduce( - (max, node) => Math.max(max, node.height ?? 0), - 10, - ); + // throw error if any node is missing width or height + nodes.forEach((node) => { + if (!node.width || !node.height) { + throw new Error( + "Each node must have a width and a height. Node: " + node.id, + ); + } + }); nodes.forEach((node) => { dagreGraph.setNode(node.id, { width: node.width, height: node.height }); @@ -34,7 +34,6 @@ export const getLayoutedElements = ( }); dagre.layout(dagreGraph); - nodes.forEach((node) => { const nodeWithPosition = dagreGraph.node(node.id); node.targetPosition = Position.Left; diff --git a/stepwise-studio/styles/globals.css b/stepwise-studio/styles/globals.css index d24a337..8e75c6f 100644 --- a/stepwise-studio/styles/globals.css +++ b/stepwise-studio/styles/globals.css @@ -7,8 +7,8 @@ --background: 0 0% 100%; --foreground: 222.2 84% 4.9%; - --card: 0 0% 100%; - --card-foreground: 222.2 84% 4.9%; + --card: 0 0% 98%; + --card-foreground: 240 5.3% 26.1%; --popover: 0 0% 100%; --popover-foreground: 222.2 84% 4.9%; @@ -59,8 +59,8 @@ --background: 222.2 84% 4.9%; --foreground: 210 40% 98%; - --card: 222.2 84% 4.9%; - --card-foreground: 210 40% 98%; + --card: 240 5.9% 10%; + --card-foreground: 240 4.8% 95.9%; --popover: 222.2 84% 4.9%; --popover-foreground: 210 40% 98%;