"use client"; import { callServerPromise } from "./callServerPromise"; import { LoadingIcon } from "@/components/LoadingIcon"; import AutoForm, { AutoFormSubmit } from "@/components/ui/auto-form"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import type { workflowAPINodeType } from "@/db/schema"; import { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow"; import { createRun } from "@/server/createRun"; import { createDeployments } from "@/server/curdDeploments"; import type { getMachines } from "@/server/curdMachine"; import type { findFirstTableWithVersion } from "@/server/findFirstTableWithVersion"; import { Copy, ExternalLink, Info, MoreVertical, Play } from "lucide-react"; import { parseAsInteger, useQueryState } from "next-usequerystate"; import { useMemo, useState } from "react"; import { toast } from "sonner"; import useSWR from "swr"; import { z } from "zod"; export function VersionSelect({ workflow, }: { workflow: Awaited>; }) { const [version, setVersion] = useQueryState("version", { defaultValue: workflow?.versions[0].version?.toString() ?? "", }); return ( ); } export function MachineSelect({ machines, }: { machines: Awaited>; }) { const [machine, setMachine] = useQueryState("machine", { defaultValue: machines?.[0].id ?? "", }); return ( ); } export function RunWorkflowButton({ workflow, machines, }: { workflow: Awaited>; machines: Awaited>; }) { const [version] = useQueryState("version", { defaultValue: workflow?.versions[0].version ?? 1, ...parseAsInteger, }); const [machine] = useQueryState("machine", { defaultValue: machines[0].id ?? "", }); const [isLoading, setIsLoading] = useState(false); const [values, setValues] = useState>({}); const [open, setOpen] = useState(false); const schema = useMemo(() => { const workflow_version = getWorkflowVersionFromVersionIndex( workflow, version ); const inputs = getInputsFromWorkflow(workflow_version); if (!inputs) return null; return z.object({ ...Object.fromEntries( inputs?.map((x) => { return [x?.input_id, z.string().optional()]; }) ), }); }, [version]); const runWorkflow = async () => { console.log(values); const val = Object.keys(values).length > 0 ? values : undefined; const workflow_version_id = workflow?.versions.find( (x) => x.version === version )?.id; console.log(workflow_version_id); if (!workflow_version_id) return; setIsLoading(true); try { const origin = window.location.origin; await callServerPromise( createRun(origin, workflow_version_id, machine, val, true) ); // console.log(res.json()); setIsLoading(false); } catch (error) { setIsLoading(false); } setOpen(false); }; return ( Run inputs Run your workflow with custom inputs {/*
*/} {schema && (
Run {isLoading ? : }
)} {!schema && ( )} {/*
*/} {/*
{view}
*/}
); } export function CreateDeploymentButton({ workflow, machines, }: { workflow: Awaited>; machines: Awaited>; }) { const [version] = useQueryState("version", { defaultValue: workflow?.versions[0].version ?? 1, ...parseAsInteger, }); const [machine] = useQueryState("machine", { defaultValue: machines[0].id ?? "", }); const [isLoading, setIsLoading] = useState(false); const workflow_version_id = workflow?.versions.find( (x) => x.version === version )?.id; return ( { if (!workflow_version_id) return; setIsLoading(true); await callServerPromise( createDeployments( workflow.id, workflow_version_id, machine, "production" ) ); setIsLoading(false); }} > Production { if (!workflow_version_id) return; setIsLoading(true); await callServerPromise( createDeployments( workflow.id, workflow_version_id, machine, "staging" ) ); setIsLoading(false); }} > Staging ); } export function CopyWorkflowVersion({ workflow, }: { workflow: Awaited>; }) { const [version] = useQueryState("version", { defaultValue: workflow?.versions[0].version ?? 1, ...parseAsInteger, }); const workflow_version = workflow?.versions.find( (x) => x.version === version ); return ( { if (!workflow) return; // console.log(workflow_version?.workflow); workflow_version?.workflow?.nodes.forEach((x: any) => { if (x?.type === "ComfyDeploy") { x.widgets_values[1] = workflow.id; x.widgets_values[2] = workflow_version.version; } }); navigator.clipboard.writeText( JSON.stringify(workflow_version?.workflow) ); toast("Copied to clipboard"); }} > Copy (JSON) { navigator.clipboard.writeText( JSON.stringify(workflow_version?.workflow_api) ); toast("Copied to clipboard"); }} > Copy API (JSON) ); } export function getWorkflowVersionFromVersionIndex( workflow: Awaited>, version: number ) { const workflow_version = workflow?.versions.find((x) => x.version == version); return workflow_version; } export default async function fetcher( input: RequestInfo, init?: RequestInit ): Promise { const res = await fetch(input, init); return res.json(); } export function ViewWorkflowDetailsButton({ workflow, }: { workflow: Awaited>; }) { const [version] = useQueryState("version", { defaultValue: workflow?.versions[0].version ?? 1, ...parseAsInteger, }); const [isLoading, setIsLoading] = useState(false); const [open, setOpen] = useState(false); const { data, error, isLoading: isNodesIndexLoading, } = useSWR( "https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/extension-node-map.json", fetcher ); const groupedByAuxName = useMemo(() => { if (!data) return null; // console.log(data); const workflow_version = getWorkflowVersionFromVersionIndex( workflow, version ); const api = workflow_version?.workflow_api; if (!api) return null; const crossCheckedApi = Object.entries(api) .map(([_, value]) => { const classType = value.class_type; const classTypeData = Object.entries(data).find(([_, nodeArray]) => nodeArray[0].includes(classType) ); return classTypeData ? { node: value, classTypeData } : null; }) .filter((item) => item !== null); // console.log(crossCheckedApi); const groupedByAuxName = crossCheckedApi.reduce( (acc, data) => { if (!data) return acc; const { node, classTypeData } = data; const auxName = classTypeData[1][1].title_aux; // console.log(auxName); if (!acc[auxName]) { acc[auxName] = { url: classTypeData[0], node: [], }; } acc[auxName].node.push(node); return acc; }, {} as Record< string, { node: z.infer[]; url: string; } > ); // console.log(groupedByAuxName); return groupedByAuxName; }, [version, data]); return ( Workflow Details View your custom nodes, models, external files used in this workflow
File Output {groupedByAuxName && Object.entries(groupedByAuxName).map(([key, group]) => { // const filePath return ( {key} {group.node.map((x) => ( {x.class_type} ))} ); })}
{/* */} {/*
{view}
*/}
); }