diff --git a/web/drizzle/0028_futuristic_lady_deathstrike.sql b/web/drizzle/0028_futuristic_lady_deathstrike.sql new file mode 100644 index 0000000..3129f14 --- /dev/null +++ b/web/drizzle/0028_futuristic_lady_deathstrike.sql @@ -0,0 +1 @@ +ALTER TYPE "workflow_run_origin" ADD VALUE 'public-share'; \ No newline at end of file diff --git a/web/drizzle/meta/0028_snapshot.json b/web/drizzle/meta/0028_snapshot.json new file mode 100644 index 0000000..a0c819d --- /dev/null +++ b/web/drizzle/meta/0028_snapshot.json @@ -0,0 +1,738 @@ +{ + "id": "7bdeb193-ee27-40cc-8252-59ddaf505ab8", + "prevId": "dddfedc3-5b2f-4d54-a996-821945b9ff80", + "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": "cascade", + "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 + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "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 + }, + "auth_token": { + "name": "auth_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "machine_type", + "primaryKey": false, + "notNull": true, + "default": "'classic'" + }, + "status": { + "name": "status", + "type": "machine_status", + "primaryKey": false, + "notNull": true, + "default": "'ready'" + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "models": { + "name": "models", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "gpu": { + "name": "gpu", + "type": "machine_gpu", + "primaryKey": false, + "notNull": false + }, + "build_machine_instance_id": { + "name": "build_machine_instance_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "build_log": { + "name": "build_log", + "type": "text", + "primaryKey": false, + "notNull": 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 + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "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 + }, + "snapshot": { + "name": "snapshot", + "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_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", + "public-share": "public-share" + } + }, + "machine_gpu": { + "name": "machine_gpu", + "values": { + "T4": "T4", + "A10G": "A10G", + "A100": "A100" + } + }, + "machine_status": { + "name": "machine_status", + "values": { + "ready": "ready", + "building": "building", + "error": "error" + } + }, + "machine_type": { + "name": "machine_type", + "values": { + "classic": "classic", + "runpod-serverless": "runpod-serverless", + "modal-serverless": "modal-serverless", + "comfy-deploy-serverless": "comfy-deploy-serverless" + } + }, + "workflow_run_origin": { + "name": "workflow_run_origin", + "values": { + "manual": "manual", + "api": "api", + "public-share": "public-share" + } + }, + "workflow_run_status": { + "name": "workflow_run_status", + "values": { + "not-started": "not-started", + "running": "running", + "uploading": "uploading", + "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 015327a..eb5f0f0 100644 --- a/web/drizzle/meta/_journal.json +++ b/web/drizzle/meta/_journal.json @@ -197,6 +197,13 @@ "when": 1705228261543, "tag": "0027_eminent_lilith", "breakpoints": true + }, + { + "idx": 28, + "version": "5", + "when": 1705642345817, + "tag": "0028_futuristic_lady_deathstrike", + "breakpoints": true } ] } \ No newline at end of file diff --git a/web/src/app/(app)/share/[share_id]/page.tsx b/web/src/app/(app)/share/[share_id]/page.tsx index 98ee895..eddb7ab 100644 --- a/web/src/app/(app)/share/[share_id]/page.tsx +++ b/web/src/app/(app)/share/[share_id]/page.tsx @@ -1,8 +1,8 @@ import { ButtonActionMenu } from "@/components/ButtonActionLoader"; import { PublicRunOutputs, - RunWorkflowInline, } from "@/components/VersionSelect"; +import { RunWorkflowInline } from "@/components/RunWorkflowInline"; import { Card, CardContent, diff --git a/web/src/components/DeploymentDisplay.tsx b/web/src/components/DeploymentDisplay.tsx index 5705d08..b3b6341 100644 --- a/web/src/components/DeploymentDisplay.tsx +++ b/web/src/components/DeploymentDisplay.tsx @@ -61,34 +61,31 @@ const output = fetch("?run_id=" + run_id, { }).then(response => response.json()) `; -const clientTemplate = ` +const jsClientSetupTemplate = ` const client = new ComfyDeployClient({ apiBase: "", apiToken: process.env.COMFY_DEPLOY_API_KEY!, }); +`; -export async function generateTextures(scrImageId: string) { - const result = await client.run("", { - input_image: "", - }); - if (!result || !result.run_id) return { error: "run id not found" }; - return { id: result.run_id }; -} +const jsClientSetupTemplateHostedVersion = ` +const client = new ComfyDeployClient({ + apiToken: process.env.COMFY_DEPLOY_API_KEY!, +}); +`; + +const jsClientCreateRunTemplate = ` +const { run_id } = await client.run("", { + inputs: {} +}); +`; + +const jsClientCreateRunNoInputsTemplate = ` +const { run_id } = await client.run(""); `; const clientTemplate_checkStatus = ` -const run_id = ""; - -while (true) { - const run = await client.getRun(run_id); - await new Promise((resolve) => setTimeout(resolve, 3000)); - - if (!run) continue; - run.outputs.map((val) => { - if (!val.data.image) return; - }); -} - +const run = await client.getRun(run_id); `; export function DeploymentDisplay({ @@ -130,30 +127,41 @@ export function DeploymentDisplay({ {deployment.environment !== "public-share" ? ( - - - client - js - curl + + + Server Client + NodeJS Fetch + CURL
- Trigger the workflow with  + Copy and paste the ComfyDeployClient form  - comfy deploy wrapper + here
-
- Copy the wrapper to your project, and import the function -
+ Create a run via deployment id + 0 + ? jsClientCreateRunTemplate + : jsClientCreateRunNoInputsTemplate, deployment, domain, workflowInput @@ -227,7 +235,8 @@ function formatCode( codeTemplate: string, deployment: Awaited>[0], domain: string, - inputs?: ReturnType + inputs?: ReturnType, + inputsTabs?: number ) { if (inputs && inputs.length > 0) { codeTemplate = codeTemplate.replace( diff --git a/web/src/components/RunDisplay.tsx b/web/src/components/RunDisplay.tsx index c9d35cd..5f0f7da 100644 --- a/web/src/components/RunDisplay.tsx +++ b/web/src/components/RunDisplay.tsx @@ -1,6 +1,7 @@ import { LiveStatus } from "./LiveStatus"; import { RunInputs } from "@/components/RunInputs"; import { RunOutputs } from "@/components/RunOutputs"; +import { Badge } from "@/components/ui/badge"; import { Dialog, DialogContent, @@ -31,6 +32,9 @@ export async function RunDisplay({ {getRelativeTime(run.created_at)} {run.version?.version} + + {run.origin} + diff --git a/web/src/components/RunWorkflowInline.tsx b/web/src/components/RunWorkflowInline.tsx new file mode 100644 index 0000000..7033a37 --- /dev/null +++ b/web/src/components/RunWorkflowInline.tsx @@ -0,0 +1,113 @@ +"use client"; + +import { plainInputsToZod } from "../lib/workflowVersionInputsToZod"; +import { publicRunStore } from "./VersionSelect"; +import { callServerPromise } from "./callServerPromise"; +import { LoadingIcon } from "@/components/LoadingIcon"; +import AutoForm, { AutoFormSubmit } from "@/components/ui/auto-form"; +import { Button } from "@/components/ui/button"; +import type { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow"; +import { createRun } from "@/server/createRun"; +import { useAuth, useClerk } from "@clerk/nextjs"; +import { Play } from "lucide-react"; +import { useMemo, useState } from "react"; + +// For share page +export function RunWorkflowInline({ + inputs, + workflow_version_id, + machine_id, +}: { + inputs: ReturnType; + workflow_version_id: string; + machine_id: string; +}) { + const [values, setValues] = useState>({}); + const [isLoading, setIsLoading] = useState(false); + + const user = useAuth(); + const clerk = useClerk(); + + const schema = useMemo(() => { + return plainInputsToZod(inputs); + }, [inputs]); + + const { + setRunId, + loading, + setLoading: setLoading2, + setStatus, + } = publicRunStore(); + + const runWorkflow = async () => { + console.log(); + + if (!user.isSignedIn) { + clerk.openSignIn({ + redirectUrl: window.location.href, + }); + console.log("hi"); + return; + } + console.log(values); + + const val = Object.keys(values).length > 0 ? values : undefined; + setLoading2(true); + setIsLoading(true); + setStatus("preparing"); + try { + const origin = window.location.origin; + const a = await callServerPromise( + createRun({ + origin, + workflow_version_id: workflow_version_id, + machine_id: machine_id, + inputs: val, + runOrigin: "public-share", + }) + ); + if (a && !("error" in a)) { + setRunId(a.workflow_run_id); + } else { + setLoading2(false); + } + console.log(a); + setIsLoading(false); + } catch (error) { + setIsLoading(false); + setLoading2(false); + } + }; + + return ( + <> + {schema && ( + +
+ + Run + + {isLoading || loading ? : } + + +
+
+ )} + {!schema && ( + + )} + + ); +} diff --git a/web/src/components/RunsTable.tsx b/web/src/components/RunsTable.tsx index d734ddc..d869d93 100644 --- a/web/src/components/RunsTable.tsx +++ b/web/src/components/RunsTable.tsx @@ -44,8 +44,9 @@ export async function RunsTable(props: { Machine Time Version + Origin Live Status - Status + Status diff --git a/web/src/components/VersionSelect.tsx b/web/src/components/VersionSelect.tsx index 801d691..9d99036 100644 --- a/web/src/components/VersionSelect.tsx +++ b/web/src/components/VersionSelect.tsx @@ -1,9 +1,6 @@ "use client"; -import { - plainInputsToZod, - workflowVersionInputsToZod, -} from "../lib/workflowVersionInputsToZod"; +import { workflowVersionInputsToZod } from "../lib/workflowVersionInputsToZod"; import { callServerPromise } from "./callServerPromise"; import fetcher from "./fetcher"; import { LoadingIcon } from "@/components/LoadingIcon"; @@ -43,12 +40,10 @@ import { TableRow, } from "@/components/ui/table"; import type { workflowAPINodeType } from "@/db/schema"; -import type { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow"; import { checkStatus, createRun } from "@/server/createRun"; import { createDeployments } from "@/server/curdDeploments"; import type { getMachines } from "@/server/curdMachine"; import type { findFirstTableWithVersion } from "@/server/findFirstTableWithVersion"; -import { useAuth, useClerk } from "@clerk/nextjs"; import { Copy, ExternalLink, @@ -147,7 +142,7 @@ type PublicRunStore = { setStatus: (status: string) => void; }; -const publicRunStore = create((set) => ({ +export const publicRunStore = create((set) => ({ image: "", loading: false, runId: "", @@ -198,105 +193,6 @@ export function PublicRunOutputs() { ); } -export function RunWorkflowInline({ - inputs, - workflow_version_id, - machine_id, -}: { - inputs: ReturnType; - workflow_version_id: string; - machine_id: string; -}) { - const [values, setValues] = useState>({}); - const [isLoading, setIsLoading] = useState(false); - - const user = useAuth(); - const clerk = useClerk(); - - const schema = useMemo(() => { - return plainInputsToZod(inputs); - }, [inputs]); - - const { - setRunId, - loading, - setLoading: setLoading2, - setStatus, - } = publicRunStore(); - - const runWorkflow = async () => { - console.log(); - - if (!user.isSignedIn) { - clerk.openSignIn({ - redirectUrl: window.location.href, - }); - console.log("hi"); - return; - } - console.log(values); - - const val = Object.keys(values).length > 0 ? values : undefined; - setLoading2(true); - setIsLoading(true); - setStatus("preparing"); - try { - const origin = window.location.origin; - const a = await callServerPromise( - createRun({ - origin, - workflow_version_id: workflow_version_id, - machine_id: machine_id, - inputs: val, - isManualRun: true, - }) - ); - if (a && !("error" in a)) { - setRunId(a.workflow_run_id); - } else { - setLoading2(false); - } - console.log(a); - setIsLoading(false); - } catch (error) { - setIsLoading(false); - setLoading2(false); - } - }; - - return ( - <> - {schema && ( - -
- - Run - - {isLoading || loading ? : } - - -
-
- )} - {!schema && ( - - )} - - ); -} - export function RunWorkflowButton({ workflow, machines, diff --git a/web/src/components/ui/badge.tsx b/web/src/components/ui/badge.tsx index 0e58f77..4053f27 100644 --- a/web/src/components/ui/badge.tsx +++ b/web/src/components/ui/badge.tsx @@ -2,20 +2,47 @@ import { cn } from "@/lib/utils"; import { cva, type VariantProps } from "class-variance-authority"; import * as React from "react"; +const colors = { + red: "bg-red-500/15 text-red-700 group-data-[hover]:bg-red-500/25 dark:bg-red-500/10 dark:text-red-400 dark:group-data-[hover]:bg-red-500/20", + orange: + "bg-orange-500/15 text-orange-700 group-data-[hover]:bg-orange-500/25 dark:bg-orange-500/10 dark:text-orange-400 dark:group-data-[hover]:bg-orange-500/20", + amber: + "bg-amber-400/20 text-amber-700 group-data-[hover]:bg-amber-400/30 dark:bg-amber-400/10 dark:text-amber-400 dark:group-data-[hover]:bg-amber-400/15", + yellow: + "bg-yellow-400/20 text-yellow-700 group-data-[hover]:bg-yellow-400/30 dark:bg-yellow-400/10 dark:text-yellow-300 dark:group-data-[hover]:bg-yellow-400/15", + lime: "bg-lime-400/20 text-lime-700 group-data-[hover]:bg-lime-400/30 dark:bg-lime-400/10 dark:text-lime-300 dark:group-data-[hover]:bg-lime-400/15", + green: + "bg-green-500/15 text-green-700 group-data-[hover]:bg-green-500/25 dark:bg-green-500/10 dark:text-green-400 dark:group-data-[hover]:bg-green-500/20", + emerald: + "bg-emerald-500/15 text-emerald-700 group-data-[hover]:bg-emerald-500/25 dark:bg-emerald-500/10 dark:text-emerald-400 dark:group-data-[hover]:bg-emerald-500/20", + teal: "bg-teal-500/15 text-teal-700 group-data-[hover]:bg-teal-500/25 dark:bg-teal-500/10 dark:text-teal-300 dark:group-data-[hover]:bg-teal-500/20", + cyan: "bg-cyan-400/20 text-cyan-700 group-data-[hover]:bg-cyan-400/30 dark:bg-cyan-400/10 dark:text-cyan-300 dark:group-data-[hover]:bg-cyan-400/15", + sky: "bg-sky-500/15 text-sky-700 group-data-[hover]:bg-sky-500/25 dark:bg-sky-500/10 dark:text-sky-300 dark:group-data-[hover]:bg-sky-500/20", + blue: "bg-blue-500/15 text-blue-700 group-data-[hover]:bg-blue-500/25 dark:text-blue-400 dark:group-data-[hover]:bg-blue-500/25", + indigo: + "bg-indigo-500/15 text-indigo-700 group-data-[hover]:bg-indigo-500/25 dark:text-indigo-400 dark:group-data-[hover]:bg-indigo-500/20", + violet: + "bg-violet-500/15 text-violet-700 group-data-[hover]:bg-violet-500/25 dark:text-violet-400 dark:group-data-[hover]:bg-violet-500/20", + purple: + "bg-purple-500/15 text-purple-700 group-data-[hover]:bg-purple-500/25 dark:text-purple-400 dark:group-data-[hover]:bg-purple-500/20", + fuchsia: + "bg-fuchsia-400/15 text-fuchsia-700 group-data-[hover]:bg-fuchsia-400/25 dark:bg-fuchsia-400/10 dark:text-fuchsia-400 dark:group-data-[hover]:bg-fuchsia-400/20", + pink: "bg-pink-400/15 text-pink-700 group-data-[hover]:bg-pink-400/25 dark:bg-pink-400/10 dark:text-pink-400 dark:group-data-[hover]:bg-pink-400/20", + rose: "bg-rose-400/15 text-rose-700 group-data-[hover]:bg-rose-400/25 dark:bg-rose-400/10 dark:text-rose-400 dark:group-data-[hover]:bg-rose-400/20", + zinc: "bg-zinc-600/10 text-zinc-700 group-data-[hover]:bg-zinc-600/20 dark:bg-white/5 dark:text-zinc-400 dark:group-data-[hover]:bg-white/10", +}; + const badgeVariants = cva( - "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", + "inline-flex items-center gap-x-1.5 rounded-md px-2 py-0.5 text-sm/5 font-medium sm:text-xs/5 forced-colors:outline", { variants: { variant: { - default: - "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", - secondary: - "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", - success: - "border-transparent bg-green-200 text-secondary-foreground hover:bg-green-200/80", - destructive: - "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", - outline: "text-foreground", + default: colors["zinc"], + secondary: colors["zinc"], + success: colors["green"], + destructive: colors["red"], + outline: "text-foreground border", + ...colors, }, }, defaultVariants: { diff --git a/web/src/components/ui/button.tsx b/web/src/components/ui/button.tsx index 74f3985..669b444 100644 --- a/web/src/components/ui/button.tsx +++ b/web/src/components/ui/button.tsx @@ -3,34 +3,201 @@ import { Slot } from "@radix-ui/react-slot"; import { cva, type VariantProps } from "class-variance-authority"; import * as React from "react"; -const buttonVariants = cva( - "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", - { - variants: { - variant: { - default: "bg-primary text-primary-foreground hover:bg-primary/90", - destructive: - "bg-destructive text-destructive-foreground hover:bg-destructive/90", - outline: - "border border-input bg-background hover:bg-accent hover:text-accent-foreground", - secondary: - "bg-secondary text-secondary-foreground hover:bg-secondary/80", - ghost: "hover:bg-accent hover:text-accent-foreground", - link: "text-primary underline-offset-4 hover:underline", - }, - size: { - default: "h-10 px-4 py-2", - sm: "h-9 rounded-md px-3", - lg: "h-11 rounded-md px-8", - icon: "h-10 w-10", - }, +const styles = { + base: [ + // Base + "relative isolate inline-flex items-center justify-center gap-x-2 rounded-lg border text-base/6 font-semibold", + + // Sizing + "px-[calc(theme(spacing[3.5])-1px)] py-[calc(theme(spacing[2.5])-1px)] sm:px-[calc(theme(spacing.3)-1px)] sm:py-[calc(theme(spacing[1.5])-1px)] sm:text-sm/6", + + // Focus + "focus:outline-none data-[focus]:outline data-[focus]:outline-2 data-[focus]:outline-offset-2 data-[focus]:outline-blue-500", + + // Disabled + "data-[disabled]:opacity-50", + + // Icon + "[&>[data-slot=icon]]:-mx-0.5 [&>[data-slot=icon]]:my-0.5 [&>[data-slot=icon]]:size-5 [&>[data-slot=icon]]:shrink-0 [&>[data-slot=icon]]:text-[--btn-icon] [&>[data-slot=icon]]:sm:my-1 [&>[data-slot=icon]]:sm:size-4 forced-colors:[--btn-icon:ButtonText] forced-colors:data-[hover]:[--btn-icon:ButtonText]", + ], + solid: [ + // Optical border, implemented as the button background to avoid corner artifacts + "border-transparent bg-[--btn-border]", + + // Dark mode: border is rendered on `after` so background is set to button background + "dark:bg-[--btn-bg]", + + // Button background, implemented as foreground layer to stack on top of pseudo-border layer + "before:absolute before:inset-0 before:-z-10 before:rounded-[calc(theme(borderRadius.lg)-1px)] before:bg-[--btn-bg]", + + // Drop shadow, applied to the inset `before` layer so it blends with the border + "before:shadow", + + // Background color is moved to control and shadow is removed in dark mode so hide `before` pseudo + "dark:before:hidden", + + // Dark mode: Subtle white outline is applied using a border + "dark:border-white/5", + + // Shim/overlay, inset to match button foreground and used for hover state + highlight shadow + "after:absolute after:inset-0 after:-z-10 after:rounded-[calc(theme(borderRadius.lg)-1px)]", + + // Inner highlight shadow + "after:shadow-[shadow:inset_0_1px_theme(colors.white/15%)]", + + // White overlay on hover + "after:data-[active]:bg-[--btn-hover-overlay] after:data-[hover]:bg-[--btn-hover-overlay]", + + // Dark mode: `after` layer expands to cover entire button + "dark:after:-inset-px dark:after:rounded-lg", + + // Disabled + "before:data-[disabled]:shadow-none after:data-[disabled]:shadow-none", + ], + outline: [ + // Base + "border-zinc-950/10 text-zinc-950 data-[active]:bg-zinc-950/[2.5%] data-[hover]:bg-zinc-950/[2.5%]", + + // Dark mode + "dark:border-white/15 dark:text-white dark:[--btn-bg:transparent] dark:data-[active]:bg-white/5 dark:data-[hover]:bg-white/5", + + // Icon + "[--btn-icon:theme(colors.zinc.500)] data-[active]:[--btn-icon:theme(colors.zinc.700)] data-[hover]:[--btn-icon:theme(colors.zinc.700)] dark:data-[active]:[--btn-icon:theme(colors.zinc.400)] dark:data-[hover]:[--btn-icon:theme(colors.zinc.400)]", + ], + plain: [ + // Base + "border-transparent text-zinc-950 data-[active]:bg-zinc-950/5 data-[hover]:bg-zinc-950/5", + + // Dark mode + "dark:text-white dark:data-[active]:bg-white/10 dark:data-[hover]:bg-white/10", + + // Icon + "[--btn-icon:theme(colors.zinc.500)] data-[active]:[--btn-icon:theme(colors.zinc.700)] data-[hover]:[--btn-icon:theme(colors.zinc.700)] dark:[--btn-icon:theme(colors.zinc.500)] dark:data-[active]:[--btn-icon:theme(colors.zinc.400)] dark:data-[hover]:[--btn-icon:theme(colors.zinc.400)]", + ], + colors: { + "dark/zinc": [ + "text-white [--btn-bg:theme(colors.zinc.900)] [--btn-border:theme(colors.zinc.950/90%)] [--btn-hover-overlay:theme(colors.white/10%)]", + "dark:text-white dark:[--btn-bg:theme(colors.zinc.600)] dark:[--btn-hover-overlay:theme(colors.white/5%)]", + "[--btn-icon:theme(colors.zinc.400)] data-[active]:[--btn-icon:theme(colors.zinc.300)] data-[hover]:[--btn-icon:theme(colors.zinc.300)]", + ], + light: [ + "text-zinc-950 [--btn-bg:white] [--btn-border:theme(colors.zinc.950/10%)] [--btn-hover-overlay:theme(colors.zinc.950/2.5%)] data-[active]:[--btn-border:theme(colors.zinc.950/15%)] data-[hover]:[--btn-border:theme(colors.zinc.950/15%)]", + "dark:text-white dark:[--btn-hover-overlay:theme(colors.white/5%)] dark:[--btn-bg:theme(colors.zinc.800)]", + "[--btn-icon:theme(colors.zinc.500)] data-[active]:[--btn-icon:theme(colors.zinc.700)] data-[hover]:[--btn-icon:theme(colors.zinc.700)] dark:[--btn-icon:theme(colors.zinc.500)] dark:data-[active]:[--btn-icon:theme(colors.zinc.400)] dark:data-[hover]:[--btn-icon:theme(colors.zinc.400)]", + ], + "dark/white": [ + "text-white [--btn-bg:theme(colors.zinc.900)] [--btn-border:theme(colors.zinc.950/90%)] [--btn-hover-overlay:theme(colors.white/10%)]", + "dark:text-zinc-950 dark:[--btn-bg:white] dark:[--btn-hover-overlay:theme(colors.zinc.950/5%)]", + "[--btn-icon:theme(colors.zinc.400)] data-[active]:[--btn-icon:theme(colors.zinc.300)] data-[hover]:[--btn-icon:theme(colors.zinc.300)] dark:[--btn-icon:theme(colors.zinc.500)] dark:data-[active]:[--btn-icon:theme(colors.zinc.400)] dark:data-[hover]:[--btn-icon:theme(colors.zinc.400)]", + ], + dark: [ + "text-white [--btn-bg:theme(colors.zinc.900)] [--btn-border:theme(colors.zinc.950/90%)] [--btn-hover-overlay:theme(colors.white/10%)]", + "dark:[--btn-hover-overlay:theme(colors.white/5%)] dark:[--btn-bg:theme(colors.zinc.800)]", + "[--btn-icon:theme(colors.zinc.400)] data-[active]:[--btn-icon:theme(colors.zinc.300)] data-[hover]:[--btn-icon:theme(colors.zinc.300)]", + ], + white: [ + "text-zinc-950 [--btn-bg:white] [--btn-border:theme(colors.zinc.950/10%)] [--btn-hover-overlay:theme(colors.zinc.950/2.5%)] data-[active]:[--btn-border:theme(colors.zinc.950/15%)] data-[hover]:[--btn-border:theme(colors.zinc.950/15%)]", + "dark:[--btn-hover-overlay:theme(colors.zinc.950/5%)]", + "[--btn-icon:theme(colors.zinc.400)] data-[active]:[--btn-icon:theme(colors.zinc.500)] data-[hover]:[--btn-icon:theme(colors.zinc.500)]", + ], + zinc: [ + "text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.zinc.600)] [--btn-border:theme(colors.zinc.700/90%)]", + "dark:[--btn-hover-overlay:theme(colors.white/5%)]", + "[--btn-icon:theme(colors.zinc.400)] data-[active]:[--btn-icon:theme(colors.zinc.300)] data-[hover]:[--btn-icon:theme(colors.zinc.300)]", + ], + indigo: [ + "text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.indigo.500)] [--btn-border:theme(colors.indigo.600/90%)]", + "[--btn-icon:theme(colors.indigo.300)] data-[active]:[--btn-icon:theme(colors.indigo.200)] data-[hover]:[--btn-icon:theme(colors.indigo.200)]", + ], + cyan: [ + "text-cyan-950 [--btn-bg:theme(colors.cyan.300)] [--btn-border:theme(colors.cyan.400/80%)] [--btn-hover-overlay:theme(colors.white/25%)]", + "[--btn-icon:theme(colors.cyan.500)]", + ], + red: [ + "text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.red.600)] [--btn-border:theme(colors.red.700/90%)]", + "[--btn-icon:theme(colors.red.300)] data-[active]:[--btn-icon:theme(colors.red.200)] data-[hover]:[--btn-icon:theme(colors.red.200)]", + ], + orange: [ + "text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.orange.500)] [--btn-border:theme(colors.orange.600/90%)]", + "[--btn-icon:theme(colors.orange.300)] data-[active]:[--btn-icon:theme(colors.orange.200)] data-[hover]:[--btn-icon:theme(colors.orange.200)]", + ], + amber: [ + "text-amber-950 [--btn-hover-overlay:theme(colors.white/25%)] [--btn-bg:theme(colors.amber.400)] [--btn-border:theme(colors.amber.500/80%)]", + "[--btn-icon:theme(colors.amber.600)]", + ], + yellow: [ + "text-yellow-950 [--btn-hover-overlay:theme(colors.white/25%)] [--btn-bg:theme(colors.yellow.300)] [--btn-border:theme(colors.yellow.400/80%)]", + "[--btn-icon:theme(colors.yellow.600)] data-[active]:[--btn-icon:theme(colors.yellow.700)] data-[hover]:[--btn-icon:theme(colors.yellow.700)]", + ], + lime: [ + "text-lime-950 [--btn-hover-overlay:theme(colors.white/25%)] [--btn-bg:theme(colors.lime.300)] [--btn-border:theme(colors.lime.400/80%)]", + "[--btn-icon:theme(colors.lime.600)] data-[active]:[--btn-icon:theme(colors.lime.700)] data-[hover]:[--btn-icon:theme(colors.lime.700)]", + ], + green: [ + "text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.green.600)] [--btn-border:theme(colors.green.700/90%)]", + "[--btn-icon:theme(colors.white/60%)] data-[active]:[--btn-icon:theme(colors.white/80%)] data-[hover]:[--btn-icon:theme(colors.white/80%)]", + ], + emerald: [ + "text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.emerald.600)] [--btn-border:theme(colors.emerald.700/90%)]", + "[--btn-icon:theme(colors.white/60%)] data-[active]:[--btn-icon:theme(colors.white/80%)] data-[hover]:[--btn-icon:theme(colors.white/80%)]", + ], + teal: [ + "text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.teal.600)] [--btn-border:theme(colors.teal.700/90%)]", + "[--btn-icon:theme(colors.white/60%)] data-[active]:[--btn-icon:theme(colors.white/80%)] data-[hover]:[--btn-icon:theme(colors.white/80%)]", + ], + sky: [ + "text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.sky.500)] [--btn-border:theme(colors.sky.600/80%)]", + "[--btn-icon:theme(colors.white/60%)] data-[active]:[--btn-icon:theme(colors.white/80%)] data-[hover]:[--btn-icon:theme(colors.white/80%)]", + ], + blue: [ + "text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.blue.600)] [--btn-border:theme(colors.blue.700/90%)]", + "[--btn-icon:theme(colors.blue.400)] data-[active]:[--btn-icon:theme(colors.blue.300)] data-[hover]:[--btn-icon:theme(colors.blue.300)]", + ], + violet: [ + "text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.violet.500)] [--btn-border:theme(colors.violet.600/90%)]", + "[--btn-icon:theme(colors.violet.300)] data-[active]:[--btn-icon:theme(colors.violet.200)] data-[hover]:[--btn-icon:theme(colors.violet.200)]", + ], + purple: [ + "text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.purple.500)] [--btn-border:theme(colors.purple.600/90%)]", + "[--btn-icon:theme(colors.purple.300)] data-[active]:[--btn-icon:theme(colors.purple.200)] data-[hover]:[--btn-icon:theme(colors.purple.200)]", + ], + fuchsia: [ + "text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.fuchsia.500)] [--btn-border:theme(colors.fuchsia.600/90%)]", + "[--btn-icon:theme(colors.fuchsia.300)] data-[active]:[--btn-icon:theme(colors.fuchsia.200)] data-[hover]:[--btn-icon:theme(colors.fuchsia.200)]", + ], + pink: [ + "text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.pink.500)] [--btn-border:theme(colors.pink.600/90%)]", + "[--btn-icon:theme(colors.pink.300)] data-[active]:[--btn-icon:theme(colors.pink.200)] data-[hover]:[--btn-icon:theme(colors.pink.200)]", + ], + rose: [ + "text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.rose.500)] [--btn-border:theme(colors.rose.600/90%)]", + "[--btn-icon:theme(colors.rose.300)] data-[active]:[--btn-icon:theme(colors.rose.200)] data-[hover]:[--btn-icon:theme(colors.rose.200)]", + ], + }, +}; + +const buttonVariants = cva(styles.base, { + variants: { + variant: { + default: [...styles.solid, ...styles.colors.zinc], + destructive: [...styles.solid, ...styles.colors.red], + outline: styles.outline, + secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: styles.plain, + link: "text-primary underline-offset-4 hover:underline", }, - defaultVariants: { - variant: "default", - size: "default", + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10", }, - } -); + }, + defaultVariants: { + variant: "default", + size: "default", + }, +}); export interface ButtonProps extends React.ButtonHTMLAttributes, diff --git a/web/src/db/schema.ts b/web/src/db/schema.ts index 7ad3bd8..97a62ae 100644 --- a/web/src/db/schema.ts +++ b/web/src/db/schema.ts @@ -103,8 +103,12 @@ export const deploymentEnvironment = pgEnum("deployment_environment", [ export const workflowRunOrigin = pgEnum("workflow_run_origin", [ "manual", "api", + "public-share", ]); +export const WorkflowRunOriginSchema = z.enum(workflowRunOrigin.enumValues); +export type WorkflowRunOriginType = z.infer; + export const machineGPUOptions = pgEnum("machine_gpu", ["T4", "A10G", "A100"]); export const machinesType = pgEnum("machine_type", [ diff --git a/web/src/routes/registerCreateRunRoute.ts b/web/src/routes/registerCreateRunRoute.ts index bbef4f9..376c8d4 100644 --- a/web/src/routes/registerCreateRunRoute.ts +++ b/web/src/routes/registerCreateRunRoute.ts @@ -81,7 +81,7 @@ export const registerCreateRunRoute = (app: App) => { workflow_version_id: deploymentData.version, machine_id: deploymentData.machine, inputs, - isManualRun: false, + runOrigin: "api", apiUser: apiKeyTokenData, }); diff --git a/web/src/server/createRun.ts b/web/src/server/createRun.ts index bb1a501..6022918 100644 --- a/web/src/server/createRun.ts +++ b/web/src/server/createRun.ts @@ -2,7 +2,11 @@ import { withServerPromise } from "./withServerPromise"; import { db } from "@/db/db"; -import type { MachineType, WorkflowVersionType } from "@/db/schema"; +import type { + MachineType, + WorkflowRunOriginType, + WorkflowVersionType, +} from "@/db/schema"; import { machinesTable, workflowRunsTable } from "@/db/schema"; import type { APIKeyUserType } from "@/server/APIKeyBodyRequest"; import { getRunsData } from "@/server/getRunsData"; @@ -19,14 +23,14 @@ export const createRun = withServerPromise( workflow_version_id, machine_id, inputs, - isManualRun, + runOrigin, apiUser, }: { origin: string; workflow_version_id: string | WorkflowVersionType; machine_id: string | MachineType; inputs?: Record; - isManualRun?: boolean; + runOrigin?: WorkflowRunOriginType; apiUser?: APIKeyUserType; }) => { const machine = @@ -109,7 +113,7 @@ export const createRun = withServerPromise( workflow_version_id: workflow_version_data.id, workflow_inputs: inputs, machine_id: machine.id, - origin: isManualRun ? "manual" : "api", + origin: runOrigin, }) .returning();