>;
+}) {
+ return (
+
+ Machine Status
+ {props.machines.map((x) => (
+
+ ))}
+
+ );
+}
+
+function MachineWS({
+ machine,
+}: {
+ machine: Awaited>[0];
+}) {
+ const { addData } = useStore();
+ const wsEndpoint = machine.endpoint.replace(/^http/, "ws");
+ const { lastMessage, readyState } = useWebSocket(
+ `${wsEndpoint}/comfy-deploy/ws`,
+ {
+ reconnectAttempts: 10,
+ reconnectInterval: 1000,
+ }
+ );
+
+ const connectionStatus = {
+ [ReadyState.CONNECTING]: "Connecting",
+ [ReadyState.OPEN]: "Open",
+ [ReadyState.CLOSING]: "Closing",
+ [ReadyState.CLOSED]: "Closed",
+ [ReadyState.UNINSTANTIATED]: "Uninstantiated",
+ }[readyState];
+
+ useEffect(() => {
+ if (!lastMessage?.data) return;
+
+ const message = JSON.parse(lastMessage.data);
+ console.log(message.event, message);
+
+ if (message.data?.prompt_id) {
+ addData(message.data.prompt_id, message);
+ }
+ }, [lastMessage]);
+
+ return (
+
+ {machine.name} - {connectionStatus}
+
+ );
+}
diff --git a/web/src/components/NavbarRight.tsx b/web/src/components/NavbarRight.tsx
index 91127e9..14364ca 100644
--- a/web/src/components/NavbarRight.tsx
+++ b/web/src/components/NavbarRight.tsx
@@ -1,6 +1,6 @@
"use client";
-import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
+import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { usePathname } from "next/navigation";
import { useRouter } from "next/navigation";
diff --git a/web/src/components/RunDisplay.tsx b/web/src/components/RunDisplay.tsx
new file mode 100644
index 0000000..4f47465
--- /dev/null
+++ b/web/src/components/RunDisplay.tsx
@@ -0,0 +1,27 @@
+"use client";
+
+import type { findAllRuns } from "../app/[workflow_id]/page";
+import { StatusBadge } from "../app/[workflow_id]/page";
+import { useStore } from "@/components/MachinesWS";
+import { TableCell, TableRow } from "@/components/ui/table";
+import { getRelativeTime } from "@/lib/getRelativeTime";
+
+export function RunDisplay({
+ run,
+}: {
+ run: Awaited>[0];
+}) {
+ const data = useStore((state) => state.data.find((x) => x.id === run.id));
+
+ return (
+
+ {run.version.version}
+ {run.machine.name}
+ {getRelativeTime(run.created_at)}
+ {data ? data.json.event : "-"}
+
+
+
+
+ );
+}
diff --git a/web/src/components/VersionSelect.tsx b/web/src/components/VersionSelect.tsx
index 2f901ed..f2cb7d2 100644
--- a/web/src/components/VersionSelect.tsx
+++ b/web/src/components/VersionSelect.tsx
@@ -12,6 +12,7 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
+import { createRun } from "@/server/createRun";
import type { getMachines } from "@/server/curdMachine";
import { Play } from "lucide-react";
import { parseAsInteger, useQueryState } from "next-usequerystate";
@@ -101,17 +102,15 @@ export function RunWorkflowButton({
className="gap-2"
disabled={isLoading}
onClick={async () => {
+ const workflow_version_id = workflow?.versions.find(
+ (x) => x.version === version
+ )?.id;
+ if (!workflow_version_id) return;
+
setIsLoading(true);
try {
- await fetch(`/api/create-run`, {
- method: "POST",
- body: JSON.stringify({
- workflow_version_id: workflow?.versions.find(
- (x) => x.version === version
- )?.id,
- machine_id: machine,
- }),
- });
+ const origin = window.location.origin;
+ await createRun(origin, workflow_version_id, machine);
setIsLoading(false);
} catch (error) {
setIsLoading(false);
diff --git a/web/src/server/createRun.ts b/web/src/server/createRun.ts
new file mode 100644
index 0000000..bfd922f
--- /dev/null
+++ b/web/src/server/createRun.ts
@@ -0,0 +1,95 @@
+"use server";
+
+import { ComfyAPI_Run } from "../app/api/create-run/route";
+import { db } from "@/db/db";
+import { workflowRunsTable } from "@/db/schema";
+import { eq } from "drizzle-orm";
+import { revalidatePath } from "next/cache";
+import { NextResponse } from "next/server";
+import "server-only";
+
+export async function createRun(
+ origin: string,
+ workflow_version_id: string,
+ machine_id: string
+) {
+ const machine = await db.query.machinesTable.findFirst({
+ where: eq(workflowRunsTable.id, machine_id),
+ });
+
+ if (!machine) {
+ return new Response("Machine not found", {
+ status: 404,
+ });
+ }
+
+ const workflow_version_data =
+ // workflow_version_id
+ // ?
+ await db.query.workflowVersionTable.findFirst({
+ where: eq(workflowRunsTable.id, workflow_version_id),
+ });
+ // : workflow_version != undefined
+ // ? await db.query.workflowVersionTable.findFirst({
+ // where: and(
+ // eq(workflowVersionTable.version, workflow_version),
+ // eq(workflowVersionTable.workflow_id)
+ // ),
+ // })
+ // : null;
+ if (!workflow_version_data) {
+ return new Response("Workflow version not found", {
+ status: 404,
+ });
+ }
+
+ const comfyui_endpoint = `${machine.endpoint}/comfy-deploy/run`;
+
+ // Sending to comfyui
+ const result = await fetch(comfyui_endpoint, {
+ method: "POST",
+ // headers: {
+ // "Content-Type": "application/json",
+ // },
+ body: JSON.stringify({
+ workflow_api: workflow_version_data.workflow_api,
+ status_endpoint: `${origin}/api/update-run`,
+ }),
+ })
+ .then(async (res) => ComfyAPI_Run.parseAsync(await res.json()))
+ .catch((error) => {
+ console.error(error);
+ return new Response(error.details, {
+ status: 500,
+ });
+ });
+
+ console.log(result);
+
+ // return the error
+ if (result instanceof Response) {
+ return result;
+ }
+
+ // Add to our db
+ const workflow_run = await db
+ .insert(workflowRunsTable)
+ .values({
+ id: result.prompt_id,
+ workflow_id: workflow_version_data.workflow_id,
+ workflow_version_id: workflow_version_data.id,
+ machine_id,
+ })
+ .returning();
+
+ revalidatePath(`/${workflow_version_data.workflow_id}`);
+
+ return NextResponse.json(
+ {
+ workflow_run_id: workflow_run[0].id,
+ },
+ {
+ status: 200,
+ }
+ );
+}
diff --git a/web/src/server/curdMachine.ts b/web/src/server/curdMachine.ts
index 10a1aec..53917ab 100644
--- a/web/src/server/curdMachine.ts
+++ b/web/src/server/curdMachine.ts
@@ -1,7 +1,7 @@
"use server";
import { db } from "@/db/db";
-import { machinesTable, workflowTable } from "@/db/schema";
+import { machinesTable } from "@/db/schema";
import { auth } from "@clerk/nextjs";
import { eq } from "drizzle-orm";
import { revalidatePath } from "next/cache";