Skip to content

Commit

Permalink
settings dialog workflow saving/updating & handle empty workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
radityaharya committed Feb 4, 2024
1 parent c17429d commit 3122007
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 66 deletions.
10 changes: 10 additions & 0 deletions src/app/flow/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,16 @@ function Builder({ searchParams }: { searchParams: any }) {
toast.success(
`Flow '${flowId}' loaded with ${nodes.length} nodes and ${edges.length} edges`,
);
} else {
setFlowState({
id: flowId,
name: name ?? "",
description: description ?? "",
workflow: workflowData.workflow,
});
toast.info(
`Flow '${flowId}' loaded with no nodes or edges. Please add some nodes and edges to continue.`,
);
}
}
}, [workflowData, workflowError]);
Expand Down
29 changes: 20 additions & 9 deletions src/app/utils/reactFlowToWorkflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import useStore from "../states/store";
import { type Node, type Edge } from "@xyflow/react";
import { validateWorkflow } from "./validateWorkflow";
import { generate } from "random-words";
import { toast } from "sonner";

type ReactFlowToWorkflowInput = {
nodes: Node[];
Expand Down Expand Up @@ -114,15 +115,25 @@ export default async function reactFlowToWorkflow({
connections: [],
};

nodes = filterNodes(nodes);
addNodesToWorkflow(nodes, workflowObject);
addEdgesToWorkflow(edges, workflowObject);
setNodesAsSources(workflowObject);

removeUnnecessaryData(workflowObject.sources);
removeUnnecessaryData(workflowObject.operations);

const { valid, errors } = await validateWorkflow(workflowObject);
let [valid, errors] = [true, {}];
if (nodes.length > 0 && edges.length > 0) {
nodes = filterNodes(nodes);
addNodesToWorkflow(nodes, workflowObject);
addEdgesToWorkflow(edges, workflowObject);
setNodesAsSources(workflowObject);

removeUnnecessaryData(workflowObject.sources);
removeUnnecessaryData(workflowObject.operations);
const response = await validateWorkflow(workflowObject);
valid = response.valid;
errors = response.errors;
if (!valid) {
throw new Error("Workflow is not valid");
}
} else {
toast.error("No workflow provided");
valid = false;
}

console.log("workflow", workflowObject);

Expand Down
178 changes: 121 additions & 57 deletions src/components/settingsDialog/tabs/General.tsx
Original file line number Diff line number Diff line change
@@ -1,73 +1,137 @@
import { Copy, Info } from "lucide-react";
import React from "react";
import React, { useEffect } from "react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
import useClipboard from "@/hooks/useClipboard";
import useStore from "~/app/states/store";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import * as z from "zod";
import { toast } from "sonner";
import reactFlowToWorkflow from "@/app/utils/reactFlowToWorkflow";
import { saveWorkflow } from "@/app/utils/saveWorkflow";
import { useRouter } from "next/navigation";

const formSchema = z.object({
name: z.string().min(1, {
message: "Name is required.",
}),
description: z.string().default(""),
});

const General = () => {
const { copied, copyToClipboard } = useClipboard();
const { flowState, setFlowState, nodes, edges } = useStore((state) => ({
flowState: state.flowState,
setFlowState: state.setFlowState,
nodes: state.nodes,
edges: state.edges,
}));

const form = useForm({
resolver: zodResolver(formSchema),
shouldUnregister: false,
mode: "all",
});

const { formState, register, handleSubmit } = form;
const router = useRouter();

const onSubmit = async (data: any) => {
setFlowState({
...flowState,
name: data.name,
description: data.description,
});
const { workflowResponse, errors } = await reactFlowToWorkflow({
nodes,
edges,
});
const saveResponse = await saveWorkflow(workflowResponse);
setFlowState({
description: data.description,
name: data.name,
id: saveResponse.id,
});
if (saveResponse) {
toast.success(flowState.id ? "Workflow updated" : "Workflow created");
}
router.push(`/flow?id=${saveResponse.id}`);
};

useEffect(() => {
console.log(flowState);
if (flowState) {
form.setValue("name", flowState.name);
form.setValue("description", flowState.description);
}
}, [flowState]);

return (
<div className="flex flex-col gap-4">
<h2 className="mb-2 text-xl font-semibold leading-none tracking-tight">
Workflow Info
</h2>
<div className="space-y-1">
<Label htmlFor="name">Name</Label>
<Input
id="name"
placeholder="My Workflow"
className="w-full"
data-1p-ignore
/>
</div>
<div className="space-y-1">
<Label htmlFor="short-desc">Description</Label>
<Input
id="short-desc"
placeholder="A short description for your workflow"
className="w-full"
data-1p-ignore
/>
</div>
<div className="space-y-1">
<Label htmlFor="workflow-id">Workflow ID</Label>
<div
className="group flex h-10 w-full cursor-copy flex-row justify-between rounded-md border border-input bg-white/5 px-3 py-2 text-sm outline-1 outline-slate-700 ring-offset-background hover:border-accent hover:outline"
onClick={() =>
copyToClipboard("1f77c5cb-faee-4b79-aec3-8fba9f3b7711")
}
>
1f77c5cb-faee-4b79-aec3-8fba9f3b7711
<div>
{copied ? (
<div className="flex items-center gap-2 opacity-50 transition-all duration-200 group-hover:opacity-80">
Copied!
<Info
size={20}
className="opacity-50 transition-all duration-200 group-hover:opacity-80"
/>
</div>
) : (
<div className="flex items-center gap-2 opacity-50 transition-all duration-200 group-hover:opacity-80">
Click to copy
<Copy
size={20}
className="opacity-50 transition-all duration-200 group-hover:opacity-80"
/>
</div>
)}
<form onSubmit={handleSubmit(onSubmit)}>
<div className="flex flex-col gap-4">
<h2 className="mb-2 text-xl font-semibold leading-none tracking-tight">
Workflow Info
</h2>
<div className="space-y-1">
<Label htmlFor="name">Name</Label>
<Input
{...register("name")}
id="name"
placeholder="My Workflow"
className="w-full"
data-1p-ignore
/>
</div>
<div className="space-y-1">
<Label htmlFor="short-desc">Description</Label>
<Input
{...register("description")}
id="short-desc"
placeholder="A short description for your workflow"
className="w-full"
data-1p-ignore
/>
</div>
<div className="space-y-1">
<Label htmlFor="workflow-id">Workflow ID</Label>
<div
className="group flex h-10 w-full cursor-copy flex-row justify-between rounded-md border border-input bg-white/5 px-3 py-2 text-sm outline-1 outline-slate-700 ring-offset-background hover:border-accent hover:outline"
onClick={() =>
copyToClipboard("1f77c5cb-faee-4b79-aec3-8fba9f3b7711")
}
>
<p className="opacity-80">{flowState?.id}</p>
<div>
{copied ? (
<div className="flex items-center gap-2 opacity-50 transition-all duration-200 group-hover:opacity-80">
Copied!
<Info
size={20}
className="opacity-50 transition-all duration-200 group-hover:opacity-80"
/>
</div>
) : (
<div className="flex items-center gap-2 opacity-50 transition-all duration-200 group-hover:opacity-80">
Click to copy
<Copy
size={20}
className="opacity-50 transition-all duration-200 group-hover:opacity-80"
/>
</div>
)}
</div>
</div>
<p className="text-xs text-muted-foreground opacity-80">
Use this ID to reference your workflow in the API
</p>
</div>
<p className="text-xs text-muted-foreground opacity-80">
Use this ID to reference your workflow in the API
</p>
<Button size="sm" className="w-[fit-content]" type="submit">
{flowState.id ? "Update workflow" : "Create workflow"}
</Button>
</div>
<Button size="sm" className="w-[fit-content]">
Save changes
</Button>
</div>
</form>
);
};

Expand Down

0 comments on commit 3122007

Please sign in to comment.