diff --git a/web/drizzle/0012_exotic_sumo.sql b/web/drizzle/0012_exotic_sumo.sql new file mode 100644 index 0000000..83c23fa --- /dev/null +++ b/web/drizzle/0012_exotic_sumo.sql @@ -0,0 +1 @@ +ALTER TABLE "comfyui_deploy"."machines" ADD COLUMN "disabled" boolean DEFAULT false NOT NULL; \ No newline at end of file diff --git a/web/drizzle/meta/0012_snapshot.json b/web/drizzle/meta/0012_snapshot.json new file mode 100644 index 0000000..045acd9 --- /dev/null +++ b/web/drizzle/meta/0012_snapshot.json @@ -0,0 +1,642 @@ +{ + "id": "2e7e5e52-84ad-46fc-a899-fd9464995b9c", + "prevId": "d0939fc6-9073-4277-8406-ec609494b507", + "version": "5", + "dialect": "pg", + "tables": { + "api_keys": { + "name": "api_keys", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "revoked": { + "name": "revoked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "api_keys_user_id_users_id_fk": { + "name": "api_keys_user_id_users_id_fk", + "tableFrom": "api_keys", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_keys_key_unique": { + "name": "api_keys_key_unique", + "nullsNotDistinct": false, + "columns": [ + "key" + ] + } + } + }, + "deployments": { + "name": "deployments", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "environment": { + "name": "environment", + "type": "deployment_environment", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "deployments_user_id_users_id_fk": { + "name": "deployments_user_id_users_id_fk", + "tableFrom": "deployments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_workflow_version_id_workflow_versions_id_fk": { + "name": "deployments_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "deployments", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "deployments_workflow_id_workflows_id_fk": { + "name": "deployments_workflow_id_workflows_id_fk", + "tableFrom": "deployments", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "deployments_machine_id_machines_id_fk": { + "name": "deployments_machine_id_machines_id_fk", + "tableFrom": "deployments", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "machines": { + "name": "machines", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "disabled": { + "name": "disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "machines_user_id_users_id_fk": { + "name": "machines_user_id_users_id_fk", + "tableFrom": "machines", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_run_outputs": { + "name": "workflow_run_outputs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_outputs_run_id_workflow_runs_id_fk": { + "name": "workflow_run_outputs_run_id_workflow_runs_id_fk", + "tableFrom": "workflow_run_outputs", + "tableTo": "workflow_runs", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_runs": { + "name": "workflow_runs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "workflow_inputs": { + "name": "workflow_inputs", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "origin": { + "name": "origin", + "type": "workflow_run_origin", + "primaryKey": false, + "notNull": true, + "default": "'api'" + }, + "status": { + "name": "status", + "type": "workflow_run_status", + "primaryKey": false, + "notNull": true, + "default": "'not-started'" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_runs_workflow_version_id_workflow_versions_id_fk": { + "name": "workflow_runs_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workflow_runs_workflow_id_workflows_id_fk": { + "name": "workflow_runs_workflow_id_workflows_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_runs_machine_id_machines_id_fk": { + "name": "workflow_runs_machine_id_machines_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflows": { + "name": "workflows", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflows_user_id_users_id_fk": { + "name": "workflows_user_id_users_id_fk", + "tableFrom": "workflows", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_versions": { + "name": "workflow_versions", + "schema": "comfyui_deploy", + "columns": { + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow": { + "name": "workflow", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_api": { + "name": "workflow_api", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_versions_workflow_id_workflows_id_fk": { + "name": "workflow_versions_workflow_id_workflows_id_fk", + "tableFrom": "workflow_versions", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": { + "deployment_environment": { + "name": "deployment_environment", + "values": { + "staging": "staging", + "production": "production" + } + }, + "workflow_run_origin": { + "name": "workflow_run_origin", + "values": { + "manual": "manual", + "api": "api" + } + }, + "workflow_run_status": { + "name": "workflow_run_status", + "values": { + "not-started": "not-started", + "running": "running", + "success": "success", + "failed": "failed" + } + } + }, + "schemas": { + "comfyui_deploy": "comfyui_deploy" + }, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/web/drizzle/meta/_journal.json b/web/drizzle/meta/_journal.json index 44c5c84..730786c 100644 --- a/web/drizzle/meta/_journal.json +++ b/web/drizzle/meta/_journal.json @@ -85,6 +85,13 @@ "when": 1702960221042, "tag": "0011_peaceful_william_stryker", "breakpoints": true + }, + { + "idx": 12, + "version": "5", + "when": 1703136669370, + "tag": "0012_exotic_sumo", + "breakpoints": true } ] } \ No newline at end of file diff --git a/web/src/app/machines/page.tsx b/web/src/app/machines/page.tsx index 4d0bf7f..3c8a640 100644 --- a/web/src/app/machines/page.tsx +++ b/web/src/app/machines/page.tsx @@ -15,7 +15,7 @@ async function MachineListServer() { return
No auth
; } - const workflow = await db.query.machinesTable.findMany({ + const machines = await db.query.machinesTable.findMany({ orderBy: desc(machinesTable.updated_at), where: eq(machinesTable.user_id, userId), }); @@ -23,16 +23,7 @@ async function MachineListServer() { return (
{/*
Machines
*/} - { - return { - id: x.id, - name: x.name, - date: x.updated_at, - endpoint: x.endpoint, - }; - })} - /> +
); } diff --git a/web/src/components/MachineList.tsx b/web/src/components/MachineList.tsx index e6aee46..8cc370c 100644 --- a/web/src/components/MachineList.tsx +++ b/web/src/components/MachineList.tsx @@ -11,6 +11,7 @@ import { FormMessage, Form, } from "./ui/form"; +import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { @@ -38,7 +39,13 @@ import { TableHeader, TableRow, } from "@/components/ui/table"; -import { addMachine, deleteMachine } from "@/server/curdMachine"; +import type { MachineType } from "@/db/schema"; +import { + addMachine, + deleteMachine, + disableMachine, + enableMachine, +} from "@/server/curdMachine"; import { zodResolver } from "@hookform/resolvers/zod"; import type { ColumnDef, @@ -59,12 +66,7 @@ import * as React from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; -export type Machine = { - id: string; - name: string; - endpoint: string; - date: Date; -}; +export type Machine = MachineType; export const columns: ColumnDef[] = [ { @@ -106,7 +108,12 @@ export const columns: ColumnDef[] = [ cell: ({ row }) => { return ( // - row.getValue("name") +
+
{row.getValue("name")}
+ {row.original.disabled && ( + Disabled + )} +
//
); }, @@ -137,7 +144,7 @@ export const columns: ColumnDef[] = [ }, cell: ({ row }) => (
- {getRelativeTime(row.original.date)} + {getRelativeTime(row.original.updated_at)}
), }, @@ -146,7 +153,7 @@ export const columns: ColumnDef[] = [ id: "actions", enableHiding: false, cell: ({ row }) => { - const workflow = row.original; + const machine = row.original; return ( @@ -161,11 +168,29 @@ export const columns: ColumnDef[] = [ { - callServerPromise(deleteMachine(workflow.id)); + callServerPromise(deleteMachine(machine.id)); }} > Delete Machine + {machine.disabled ? ( + { + callServerPromise(enableMachine(machine.id)); + }} + > + Enable Machine + + ) : ( + { + callServerPromise(disableMachine(machine.id)); + }} + > + Disable Machine + + )} {/* View customer View payment details */} diff --git a/web/src/db/schema.ts b/web/src/db/schema.ts index 778d7d0..734ebb0 100644 --- a/web/src/db/schema.ts +++ b/web/src/db/schema.ts @@ -176,6 +176,7 @@ export const machinesTable = dbSchema.table("machines", { endpoint: text("endpoint").notNull(), created_at: timestamp("created_at").defaultNow().notNull(), updated_at: timestamp("updated_at").defaultNow().notNull(), + disabled: boolean("disabled").default(false).notNull(), }); export const deploymentsTable = dbSchema.table("deployments", { @@ -227,3 +228,4 @@ export const apiKeyTable = dbSchema.table("api_keys", { export type UserType = InferSelectModel; export type WorkflowType = InferSelectModel; +export type MachineType = InferSelectModel; diff --git a/web/src/server/createRun.ts b/web/src/server/createRun.ts index 895af33..d0c56ec 100644 --- a/web/src/server/createRun.ts +++ b/web/src/server/createRun.ts @@ -1,12 +1,12 @@ "use server"; +import { withServerPromise } from "./withServerPromise"; import { db } from "@/db/db"; -import { workflowRunsTable } from "@/db/schema"; +import { machinesTable, workflowRunsTable } from "@/db/schema"; import { ComfyAPI_Run } from "@/types/ComfyAPI_Run"; -import { eq } from "drizzle-orm"; +import { and, eq } from "drizzle-orm"; import { revalidatePath } from "next/cache"; import "server-only"; -import { withServerPromise } from "./withServerPromise"; export const createRun = withServerPromise( async ( @@ -14,20 +14,24 @@ export const createRun = withServerPromise( workflow_version_id: string, machine_id: string, inputs?: Record, - isManualRun?: boolean, + isManualRun?: boolean ) => { const machine = await db.query.machinesTable.findFirst({ - where: eq(workflowRunsTable.id, machine_id), + where: and( + eq(machinesTable.id, machine_id), + eq(machinesTable.disabled, false) + ), }); if (!machine) { throw new Error("Machine not found"); } - const workflow_version_data = - await db.query.workflowVersionTable.findFirst({ + const workflow_version_data = await db.query.workflowVersionTable.findFirst( + { where: eq(workflowRunsTable.id, workflow_version_id), - }); + } + ); if (!workflow_version_data) { throw new Error("Workflow version not found"); @@ -79,7 +83,7 @@ export const createRun = withServerPromise( workflow_version_id: workflow_version_data.id, workflow_inputs: inputs, machine_id, - origin: isManualRun ? "manual" : "api" + origin: isManualRun ? "manual" : "api", }) .returning(); @@ -89,5 +93,5 @@ export const createRun = withServerPromise( workflow_run_id: workflow_run[0].id, message: "Successful workflow run", }; - }, + } ); diff --git a/web/src/server/curdMachine.ts b/web/src/server/curdMachine.ts index 03f9dae..45feab4 100644 --- a/web/src/server/curdMachine.ts +++ b/web/src/server/curdMachine.ts @@ -1,30 +1,22 @@ "use server"; +import { withServerPromise } from "./withServerPromise"; import { db } from "@/db/db"; import { machinesTable } from "@/db/schema"; import { auth } from "@clerk/nextjs"; -import { eq } from "drizzle-orm"; +import { and, eq } from "drizzle-orm"; import { revalidatePath } from "next/cache"; import "server-only"; -// export async function addMachine(form: FormData) { -// const name = form.get("name") as string; -// const endpoint = form.get("endpoint") as string; - -// await db.insert(machinesTable).values({ -// name, -// endpoint, -// }); -// revalidatePath("/machines"); -// } - export async function getMachines() { const { userId } = auth(); if (!userId) throw new Error("No user id"); const machines = await db .select() .from(machinesTable) - .where(eq(machinesTable.user_id, userId)); + .where( + and(eq(machinesTable.user_id, userId), eq(machinesTable.disabled, false)) + ); return machines; } @@ -40,10 +32,36 @@ export async function addMachine(name: string, endpoint: string) { revalidatePath("/machines"); } -export async function deleteMachine( - machine_id: string -): Promise<{ message: string; error?: boolean }> { - await db.delete(machinesTable).where(eq(machinesTable.id, machine_id)); - revalidatePath("/machines"); - return { message: "Machine Deleted" }; -} +export const deleteMachine = withServerPromise( + async (machine_id: string): Promise<{ message: string }> => { + await db.delete(machinesTable).where(eq(machinesTable.id, machine_id)); + revalidatePath("/machines"); + return { message: "Machine Deleted" }; + } +); + +export const disableMachine = withServerPromise( + async (machine_id: string): Promise<{ message: string }> => { + await db + .update(machinesTable) + .set({ + disabled: true, + }) + .where(eq(machinesTable.id, machine_id)); + revalidatePath("/machines"); + return { message: "Machine Disabled" }; + } +); + +export const enableMachine = withServerPromise( + async (machine_id: string): Promise<{ message: string }> => { + await db + .update(machinesTable) + .set({ + disabled: false, + }) + .where(eq(machinesTable.id, machine_id)); + revalidatePath("/machines"); + return { message: "Machine Enabled" }; + } +); diff --git a/web/src/server/deleteWorkflow.ts b/web/src/server/deleteWorkflow.ts index 526c608..d79053a 100644 --- a/web/src/server/deleteWorkflow.ts +++ b/web/src/server/deleteWorkflow.ts @@ -5,9 +5,8 @@ import { workflowTable } from "@/db/schema"; import { eq } from "drizzle-orm"; import { revalidatePath } from "next/cache"; import "server-only"; - + export async function deleteWorkflow(workflow_id: string) { await db.delete(workflowTable).where(eq(workflowTable.id, workflow_id)); revalidatePath("/"); } - \ No newline at end of file diff --git a/web/src/server/withServerPromise.ts b/web/src/server/withServerPromise.ts index b2582f9..dc5e126 100644 --- a/web/src/server/withServerPromise.ts +++ b/web/src/server/withServerPromise.ts @@ -7,6 +7,6 @@ export async function wrapServerPromise(result: Promise) { } export function withServerPromise Promise>( fn: T -): (...args: Parameters) => Promise | { error: string; }> { +): (...args: Parameters) => Promise | { error: string }> { return (...args: Parameters) => wrapServerPromise(fn(...args)); }