| import { AppNode, useEnv, useMessages, useProjectId, useStateStore } from "@/lib/state"; |
| import { Button } from "./ui/button"; |
| import { useCallback, useEffect, useState } from "react"; |
| import { generateDodoConfig } from "@/lib/config"; |
| import { useNodes, useReactFlow } from "@xyflow/react"; |
| import { useToast } from "@/hooks/use-toast"; |
| |
| export function Actions() { |
| const { toast } = useToast(); |
| const store = useStateStore(); |
| const projectId = useProjectId(); |
| const nodes = useNodes<AppNode>(); |
| const env = useEnv(); |
| const messages = useMessages(); |
| const instance = useReactFlow(); |
| const [ok, setOk] = useState(false); |
| const [loading, setLoading] = useState(false); |
| useEffect(() => { |
| setOk(!messages.some((m) => m.type === "FATAL")); |
| }, [messages, setOk]); |
| const deploy = useCallback(async () => { |
| if (projectId == null) { |
| return; |
| } |
| setLoading(true); |
| try { |
| const config = generateDodoConfig(nodes, env); |
| if (config == null) { |
| throw new Error("MUST NOT REACH!"); |
| } |
| const resp = await fetch(`/api/project/${projectId}/deploy`, { |
| method: "POST", |
| headers: { |
| "Content-Type": "application/json", |
| }, |
| body: JSON.stringify({ |
| state: JSON.stringify(instance.toObject()), |
| config, |
| }), |
| }); |
| if (resp.ok) { |
| toast({ |
| title: "Deployment succeeded", |
| }); |
| } else { |
| toast({ |
| variant: "destructive", |
| title: "Deployment failed", |
| description: await resp.text(), |
| }); |
| } |
| } catch (e) { |
| console.log(e); |
| toast({ |
| variant: "destructive", |
| title: "Deployment failed", |
| }); |
| } finally { |
| setLoading(false); |
| } |
| }, [projectId, instance, nodes, env, setLoading]); |
| const [st, setSt] = useState<string>(); |
| const save = useCallback(async () => { |
| if (projectId == null) { |
| return; |
| } |
| const resp = await fetch(`/api/project/${projectId}/saved`, { |
| method: "POST", |
| headers: { |
| "Content-Type": "application/json", |
| }, |
| body: JSON.stringify(instance.toObject()), |
| }); |
| if (resp.ok) { |
| toast({ |
| title: "Save succeeded", |
| }); |
| } else { |
| toast({ |
| variant: "destructive", |
| title: "Save failed", |
| description: await resp.text(), |
| }); |
| } |
| }, [projectId, instance, setSt]); |
| const restoreSaved = useCallback(async () => { |
| if (projectId == null) { |
| return; |
| } |
| const resp = await fetch(`/api/project/${projectId}/saved`, { |
| method: "GET", |
| }); |
| const inst = await resp.json(); |
| const { x = 0, y = 0, zoom = 1 } = inst.viewport; |
| store.setNodes(inst.nodes || []); |
| store.setEdges(inst.edges || []); |
| instance.setViewport({ x, y, zoom }); |
| }, [projectId, instance, st]); |
| const [props, setProps] = useState({}); |
| useEffect(() => { |
| if (loading) { |
| setProps({ loading: true }); |
| } else if (ok) { |
| setProps({ disabled: false }); |
| } else { |
| setProps({ disabled: true }); |
| } |
| }, [ok, loading, setProps]); |
| return ( |
| <> |
| <Button onClick={deploy} {...props}>Deploy</Button> |
| <Button onClick={save}>Save</Button> |
| <Button onClick={restoreSaved}>Restore</Button> |
| </> |
| ) |
| } |