From 163e6f0426fc733c20086fe26caf4cc0d166e553 Mon Sep 17 00:00:00 2001 From: BennyKok Date: Sat, 20 Jan 2024 12:01:39 +0800 Subject: [PATCH] feat: add share page settings dialog + add org id to deployment as well --- web/bun.lockb | Bin 552490 -> 553792 bytes web/drizzle/0029_large_frightful_four.sql | 2 + web/drizzle/0030_kind_doorman.sql | 1 + web/drizzle/meta/0029_snapshot.json | 750 +++++++++++++++++ web/drizzle/meta/0030_snapshot.json | 756 ++++++++++++++++++ web/drizzle/meta/_journal.json | 14 + web/package.json | 1 + .../(.)share/[share_id]/settings/page.tsx | 9 + web/src/app/(app)/@modal/default.tsx | 7 + web/src/app/(app)/layout.tsx | 8 +- web/src/app/(app)/share/[share_id]/page.tsx | 11 +- .../(app)/share/[share_id]/settings/page.tsx | 9 + .../workflows/[workflow_id]/@runs/page.tsx | 2 +- web/src/components/ButtonActionLoader.tsx | 10 + web/src/components/DeploymentDisplay.tsx | 205 ++--- web/src/components/DeploymentRow.tsx | 37 + web/src/components/InsertModal.tsx | 39 +- web/src/components/Main.tsx | 2 +- web/src/components/OutputPreviews.tsx | 52 ++ web/src/components/RouteRefresher.tsx | 30 +- web/src/components/RunDisplay.tsx | 4 +- web/src/components/RunWorkflowInline.tsx | 3 - web/src/components/RunsTable.tsx | 11 +- web/src/components/Section.tsx | 154 ++-- web/src/components/SharePageSettings.tsx | 85 ++ web/src/components/VersionSelect.tsx | 15 +- web/src/components/docs/ErrorPage.tsx | 26 +- web/src/components/ui/auto-form/utils.ts | 25 +- web/src/components/ui/carousel.tsx | 262 ++++++ web/src/components/useServerActionData.tsx | 26 + web/src/db/schema.ts | 33 + web/src/server/curdDeploments.ts | 60 +- 32 files changed, 2396 insertions(+), 253 deletions(-) create mode 100644 web/drizzle/0029_large_frightful_four.sql create mode 100644 web/drizzle/0030_kind_doorman.sql create mode 100644 web/drizzle/meta/0029_snapshot.json create mode 100644 web/drizzle/meta/0030_snapshot.json create mode 100644 web/src/app/(app)/@modal/(.)share/[share_id]/settings/page.tsx create mode 100644 web/src/app/(app)/@modal/default.tsx create mode 100644 web/src/app/(app)/share/[share_id]/settings/page.tsx create mode 100644 web/src/components/DeploymentRow.tsx create mode 100644 web/src/components/OutputPreviews.tsx create mode 100644 web/src/components/SharePageSettings.tsx create mode 100644 web/src/components/ui/carousel.tsx create mode 100644 web/src/components/useServerActionData.tsx diff --git a/web/bun.lockb b/web/bun.lockb index 6f53ecc9d4001c7334f34473d073bced24cf657f..cfc30ac4405d9b5feb2c4184ccf820c8b8ee5a81 100755 GIT binary patch delta 106891 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

AjV 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 F@;{nG&`baT delta 123625 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

  • q}mA_L+0)&-(n;ac%PY&!g0ubiMDEY*rFb$PdR|B7`r3W?GTh5O=#Rso& z%0RNMg}`s0YKo$R-xCtAp#`<@$DJBV!!M4AJqm)~I3l)%9x(*jBWl6Y$$%d+Y9Zj( zn#s6@1ZT2Zup4Y98$3EJZi9AfNMG{Wy6Myz%#R)WUGb!Ut2ieaKM8Zo=;B+n(r0kb|unVe6_r->~+>j-;ez^ z(eQe3+eFjq1+T rxoq#{H1r=m5ejNWW$cKkvu+TM^sc*qOnA{q7rc#)>t@6my?pk61;r75 diff --git a/web/drizzle/0029_large_frightful_four.sql b/web/drizzle/0029_large_frightful_four.sql new file mode 100644 index 0000000..d5f61d7 --- /dev/null +++ b/web/drizzle/0029_large_frightful_four.sql @@ -0,0 +1,2 @@ +ALTER TABLE "comfyui_deploy"."deployments" ADD COLUMN "description" text;--> statement-breakpoint +ALTER TABLE "comfyui_deploy"."deployments" ADD COLUMN "showcase_media" jsonb; \ No newline at end of file diff --git a/web/drizzle/0030_kind_doorman.sql b/web/drizzle/0030_kind_doorman.sql new file mode 100644 index 0000000..a2a7a8d --- /dev/null +++ b/web/drizzle/0030_kind_doorman.sql @@ -0,0 +1 @@ +ALTER TABLE "comfyui_deploy"."deployments" ADD COLUMN "org_id" text; \ No newline at end of file diff --git a/web/drizzle/meta/0029_snapshot.json b/web/drizzle/meta/0029_snapshot.json new file mode 100644 index 0000000..0f8b479 --- /dev/null +++ b/web/drizzle/meta/0029_snapshot.json @@ -0,0 +1,750 @@ +{ + "id": "a7d6a8dd-0e15-4165-98a2-de2a334455dc", + "prevId": "7bdeb193-ee27-40cc-8252-59ddaf505ab8", + "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 + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "showcase_media": { + "name": "showcase_media", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "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/0030_snapshot.json b/web/drizzle/meta/0030_snapshot.json new file mode 100644 index 0000000..ed4a5c7 --- /dev/null +++ b/web/drizzle/meta/0030_snapshot.json @@ -0,0 +1,756 @@ +{ + "id": "db06ea66-92c2-4ebe-93c1-6cb8a90ccd8b", + "prevId": "a7d6a8dd-0e15-4165-98a2-de2a334455dc", + "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 + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "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 + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "showcase_media": { + "name": "showcase_media", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "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 eb5f0f0..3bfcc76 100644 --- a/web/drizzle/meta/_journal.json +++ b/web/drizzle/meta/_journal.json @@ -204,6 +204,20 @@ "when": 1705642345817, "tag": "0028_futuristic_lady_deathstrike", "breakpoints": true + }, + { + "idx": 29, + "version": "5", + "when": 1705662714161, + "tag": "0029_large_frightful_four", + "breakpoints": true + }, + { + "idx": 30, + "version": "5", + "when": 1705716303820, + "tag": "0030_kind_doorman", + "breakpoints": true } ] } \ No newline at end of file diff --git a/web/package.json b/web/package.json index fd3fa9a..fe6e469 100644 --- a/web/package.json +++ b/web/package.json @@ -60,6 +60,7 @@ "dayjs": "^1.11.10", "drizzle-orm": "^0.29.1", "drizzle-zod": "^0.5.1", + "embla-carousel-react": "^8.0.0-rc19", "fast-glob": "^3.3.2", "flexsearch": "^0.7.31", "framer-motion": "^10.16.16", diff --git a/web/src/app/(app)/@modal/(.)share/[share_id]/settings/page.tsx b/web/src/app/(app)/@modal/(.)share/[share_id]/settings/page.tsx new file mode 100644 index 0000000..b13ec55 --- /dev/null +++ b/web/src/app/(app)/@modal/(.)share/[share_id]/settings/page.tsx @@ -0,0 +1,9 @@ +import { SharePageSettings } from "@/components/SharePageSettings"; + +export default async function Page({ + params, +}: { + params: { share_id: string }; +}) { + return ; +} diff --git a/web/src/app/(app)/@modal/default.tsx b/web/src/app/(app)/@modal/default.tsx new file mode 100644 index 0000000..dc6be5e --- /dev/null +++ b/web/src/app/(app)/@modal/default.tsx @@ -0,0 +1,7 @@ +import type { FC } from "react"; + +const Default: FC = () => { + return null; +}; + +export default Default; diff --git a/web/src/app/(app)/layout.tsx b/web/src/app/(app)/layout.tsx index 332b36c..e8ab6c9 100644 --- a/web/src/app/(app)/layout.tsx +++ b/web/src/app/(app)/layout.tsx @@ -1,15 +1,14 @@ import { Navbar } from "../../components/Navbar"; import "./globals.css"; +import { PHProvider } from "./providers"; import { TooltipProvider } from "@/components/ui/tooltip"; import { ClerkProvider } from "@clerk/nextjs"; import type { Metadata } from "next"; import meta from "next-gen/config"; import PlausibleProvider from "next-plausible"; +import dynamic from "next/dynamic"; import { Inter } from "next/font/google"; import { Toaster } from "sonner"; -import { PHProvider } from "./providers"; - -import dynamic from "next/dynamic"; const PostHogPageView = dynamic(() => import("./PostHogPageView"), { ssr: false, @@ -34,8 +33,10 @@ export const metadata: Metadata = { export default function RootLayout({ children, + modal, }: { children: React.ReactNode; + modal: React.ReactNode; }) { return ( @@ -60,6 +61,7 @@ export default function RootLayout({ {children} + {modal} diff --git a/web/src/app/(app)/share/[share_id]/page.tsx b/web/src/app/(app)/share/[share_id]/page.tsx index eddb7ab..e49922d 100644 --- a/web/src/app/(app)/share/[share_id]/page.tsx +++ b/web/src/app/(app)/share/[share_id]/page.tsx @@ -1,8 +1,6 @@ import { ButtonActionMenu } from "@/components/ButtonActionLoader"; -import { - PublicRunOutputs, -} from "@/components/VersionSelect"; import { RunWorkflowInline } from "@/components/RunWorkflowInline"; +import { PublicRunOutputs } from "@/components/VersionSelect"; import { Card, CardContent, @@ -89,6 +87,11 @@ export default async function Page({ +
    + {sharedDeployment?.description && ( + <>{sharedDeployment?.description} + )} +
    - + diff --git a/web/src/app/(app)/share/[share_id]/settings/page.tsx b/web/src/app/(app)/share/[share_id]/settings/page.tsx new file mode 100644 index 0000000..b13ec55 --- /dev/null +++ b/web/src/app/(app)/share/[share_id]/settings/page.tsx @@ -0,0 +1,9 @@ +import { SharePageSettings } from "@/components/SharePageSettings"; + +export default async function Page({ + params, +}: { + params: { share_id: string }; +}) { + return ; +} diff --git a/web/src/app/(app)/workflows/[workflow_id]/@runs/page.tsx b/web/src/app/(app)/workflows/[workflow_id]/@runs/page.tsx index cf2952a..7d8d4d0 100644 --- a/web/src/app/(app)/workflows/[workflow_id]/@runs/page.tsx +++ b/web/src/app/(app)/workflows/[workflow_id]/@runs/page.tsx @@ -17,7 +17,7 @@ export default async function Page({ Run
    - +
    diff --git a/web/src/components/ButtonActionLoader.tsx b/web/src/components/ButtonActionLoader.tsx index 331a3bb..9f517d4 100644 --- a/web/src/components/ButtonActionLoader.tsx +++ b/web/src/components/ButtonActionLoader.tsx @@ -9,6 +9,7 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; +import { useAuth, useClerk } from "@clerk/nextjs"; import { MoreVertical } from "lucide-react"; import { useRouter } from "next/navigation"; import { useState } from "react"; @@ -49,7 +50,9 @@ export function ButtonActionMenu(props: { action: () => Promise; }[]; }) { + const user = useAuth(); const [isLoading, setIsLoading] = useState(false); + const clerk = useClerk(); return ( @@ -64,6 +67,13 @@ export function ButtonActionMenu(props: { { + if (!user.isSignedIn) { + clerk.openSignIn({ + redirectUrl: window.location.href, + }); + return; + } + setIsLoading(true); await callServerPromise(action.action()); setIsLoading(false); diff --git a/web/src/components/DeploymentDisplay.tsx b/web/src/components/DeploymentDisplay.tsx index b3b6341..08d9625 100644 --- a/web/src/components/DeploymentDisplay.tsx +++ b/web/src/components/DeploymentDisplay.tsx @@ -1,6 +1,5 @@ -import { ButtonAction } from "@/components/ButtonActionLoader"; +import { DeploymentRow } from "./DeploymentRow"; import { CodeBlock } from "@/components/CodeBlock"; -import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, @@ -10,15 +9,9 @@ import { DialogTrigger, } from "@/components/ui/dialog"; import { ScrollArea } from "@/components/ui/scroll-area"; -import { TableCell, TableRow } from "@/components/ui/table"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow"; -import { getRelativeTime } from "@/lib/getRelativeTime"; -import { removePublicShareDeployment } from "@/server/curdDeploments"; import type { findAllDeployments } from "@/server/findAllRuns"; -import { ExternalLink } from "lucide-react"; -import { headers } from "next/headers"; -import Link from "next/link"; const curlTemplate = ` curl --request POST \ @@ -90,33 +83,21 @@ const run = await client.getRun(run_id); export function DeploymentDisplay({ deployment, + domain, }: { deployment: Awaited>[0]; + domain: string; }) { - const headersList = headers(); - const host = headersList.get("host") || ""; - const protocol = headersList.get("x-forwarded-proto") || ""; - const domain = `${protocol}://${host}`; - const workflowInput = getInputsFromWorkflow(deployment.version); + if (deployment.environment == "public-share") { + return ; + } + return ( - - - {deployment.environment} - - - {deployment.version?.version} - - - {deployment.machine?.name} - - - {getRelativeTime(deployment.updated_at)} - - + @@ -126,105 +107,79 @@ export function DeploymentDisplay({ Code for your deployment client - {deployment.environment !== "public-share" ? ( - - - Server Client - NodeJS Fetch - CURL - - -
    - Copy and paste the ComfyDeployClient form  - - here - -
    - - Create a run via deployment id - 0 - ? jsClientCreateRunTemplate - : jsClientCreateRunNoInputsTemplate, - deployment, - domain, - workflowInput - )} - /> - Check the status of the run, and retrieve the outputs - -
    - - Trigger the workflow - - Check the status of the run, and retrieve the outputs - - - - - - -
    - ) : ( -
    - - -
    - )} + here + + + + Create a run via deployment id + 0 + ? jsClientCreateRunTemplate + : jsClientCreateRunNoInputsTemplate, + deployment, + domain, + workflowInput + )} + /> + Check the status of the run, and retrieve the outputs + + + + Trigger the workflow + + Check the status of the run, and retrieve the outputs + + + + + + +
    diff --git a/web/src/components/DeploymentRow.tsx b/web/src/components/DeploymentRow.tsx new file mode 100644 index 0000000..232cbeb --- /dev/null +++ b/web/src/components/DeploymentRow.tsx @@ -0,0 +1,37 @@ +"use client"; + +import { TableCell, TableRow } from "@/components/ui/table"; +import { getRelativeTime } from "@/lib/getRelativeTime"; +import type { findAllDeployments } from "@/server/findAllRuns"; +import { useRouter } from "next/navigation"; + +export function DeploymentRow({ + deployment, +}: { + deployment: Awaited>[0]; +}) { + const router = useRouter(); + return ( + { + if (deployment.environment == "public-share") { + router.push(`/share/${deployment.id}/settings`); + } + }} + > + + {deployment.environment} + + + {deployment.version?.version} + + + {deployment.machine?.name} + + + {getRelativeTime(deployment.updated_at)} + + + ); +} diff --git a/web/src/components/InsertModal.tsx b/web/src/components/InsertModal.tsx index 518a297..a6b3280 100644 --- a/web/src/components/InsertModal.tsx +++ b/web/src/components/InsertModal.tsx @@ -11,6 +11,7 @@ import { DialogDescription, DialogHeader, DialogTitle, + DialogTrigger, } from "@/components/ui/dialog"; import { Tooltip, @@ -106,12 +107,14 @@ export function UpdateModal< Y extends UnknownKeysParam, Z extends ZodObject >(props: { - open: boolean; - setOpen: (open: boolean) => void; + open?: boolean; + setOpen?: (open: boolean) => void; title: string; description: string; dialogClassName?: string; - data: z.infer; + data: z.infer & { + id: string; + }; serverAction: ( data: z.infer & { id: string; @@ -119,8 +122,13 @@ export function UpdateModal< ) => Promise; formSchema: Z; fieldConfig?: FieldConfig>; + trigger?: React.ReactNode; + extraButtons?: React.ReactNode; }) { - // const [open, setOpen] = React.useState(false); + const [_open, _setOpen] = React.useState(false); + const open = props.open ?? _open; + const setOpen = props.setOpen ?? _setOpen; + const [values, setValues] = useState>>({}); const [isLoading, setIsLoading] = React.useState(false); @@ -129,10 +137,18 @@ export function UpdateModal< }, [props.data]); return ( - - {/* - {props.title} - */} + + {props.trigger ?? ( + { + setOpen(true); + }} + > + {props.trigger} + + )} {props.title} @@ -152,13 +168,14 @@ export function UpdateModal< }) ); setIsLoading(false); - props.setOpen(false); + setOpen(false); }} > -
    +
    + {props.extraButtons} Save Changes - {isLoading && } + {isLoading && }
    diff --git a/web/src/components/Main.tsx b/web/src/components/Main.tsx index b7fc746..b5473e2 100644 --- a/web/src/components/Main.tsx +++ b/web/src/components/Main.tsx @@ -69,7 +69,7 @@ export default async function Main() { - + {meta.tagline} diff --git a/web/src/components/OutputPreviews.tsx b/web/src/components/OutputPreviews.tsx new file mode 100644 index 0000000..f22e85f --- /dev/null +++ b/web/src/components/OutputPreviews.tsx @@ -0,0 +1,52 @@ +import { Card, CardContent } from "@/components/ui/card"; +import { + Carousel, + CarouselContent, + CarouselItem, + CarouselNext, + CarouselPrevious, + type CarouselApi, +} from "@/components/ui/carousel"; +import * as React from "react"; + +export function OutputPreview() { + const [api, setApi] = React.useState(); + const [current, setCurrent] = React.useState(0); + const [count, setCount] = React.useState(0); + + React.useEffect(() => { + if (!api) { + return; + } + + setCount(api.scrollSnapList().length); + setCurrent(api.selectedScrollSnap() + 1); + + api.on("select", () => { + setCurrent(api.selectedScrollSnap() + 1); + }); + }, [api]); + + return ( +
    + + + {Array.from({ length: 5 }).map((_, index) => ( + + + + {index + 1} + + + + ))} + + + + +
    + Slide {current} of {count} +
    +
    + ); +} diff --git a/web/src/components/RouteRefresher.tsx b/web/src/components/RouteRefresher.tsx index b772986..f17cb28 100644 --- a/web/src/components/RouteRefresher.tsx +++ b/web/src/components/RouteRefresher.tsx @@ -1,14 +1,21 @@ "use client"; import { LoadingIcon } from "@/components/LoadingIcon"; +import { Button } from "@/components/ui/button"; +import { RefreshCcw } from "lucide-react"; import { useRouter } from "next/navigation"; import { useEffect, useTransition } from "react"; -export function RouteRefresher(props: { interval: number }) { +export function RouteRefresher(props: { + interval: number; + autoRefresh: boolean; +}) { const [isPending, startTransition] = useTransition(); const router = useRouter(); useEffect(() => { + if (!props.autoRefresh) return; + let timeout: NodeJS.Timeout; const refresh = () => { @@ -35,7 +42,24 @@ export function RouteRefresher(props: { interval: number }) { clearTimeout(timeout); window.removeEventListener("visibilitychange", handleVisibilityChange); }; - }, [props.interval, router]); + }, [props.interval, router, props.autoRefresh]); - return
    {isPending && }
    ; + return ( +
    + {isPending && } + {!isPending && !props.autoRefresh && ( + + )} +
    + ); } diff --git a/web/src/components/RunDisplay.tsx b/web/src/components/RunDisplay.tsx index 5f0f7da..445b061 100644 --- a/web/src/components/RunDisplay.tsx +++ b/web/src/components/RunDisplay.tsx @@ -33,7 +33,9 @@ export async function RunDisplay({ {run.version?.version} - {run.origin} + + {run.origin} + diff --git a/web/src/components/RunWorkflowInline.tsx b/web/src/components/RunWorkflowInline.tsx index cf1f94b..ccb4242 100644 --- a/web/src/components/RunWorkflowInline.tsx +++ b/web/src/components/RunWorkflowInline.tsx @@ -40,13 +40,10 @@ export function RunWorkflowInline({ } = publicRunStore(); const runWorkflow = async () => { - console.log(); - if (!user.isSignedIn) { clerk.openSignIn({ redirectUrl: window.location.href, }); - console.log("hi"); return; } console.log(values); diff --git a/web/src/components/RunsTable.tsx b/web/src/components/RunsTable.tsx index d869d93..6eee49c 100644 --- a/web/src/components/RunsTable.tsx +++ b/web/src/components/RunsTable.tsx @@ -14,6 +14,7 @@ import { TableRow, } from "@/components/ui/table"; import { parseAsInteger } from "next-usequerystate"; +import { headers } from "next/headers"; const itemPerPage = 6; const pageParser = parseAsInteger.withDefault(1); @@ -69,8 +70,14 @@ export async function RunsTable(props: { export async function DeploymentsTable(props: { workflow_id: string }) { const allRuns = await findAllDeployments(props.workflow_id); + + const headersList = headers(); + const host = headersList.get("host") || ""; + const protocol = headersList.get("x-forwarded-proto") || ""; + const domain = `${protocol}://${host}`; + return ( -
    +
    A list of your deployments @@ -83,7 +90,7 @@ export async function DeploymentsTable(props: { workflow_id: string }) { {allRuns.map((run) => ( - + ))}
    diff --git a/web/src/components/Section.tsx b/web/src/components/Section.tsx index 7ac27c9..ca24cff 100644 --- a/web/src/components/Section.tsx +++ b/web/src/components/Section.tsx @@ -1,33 +1,37 @@ -import { Button, buttonVariants } from '@/components/ui/button'; -type ButtonProps = React.ComponentProps; -type LinkProps = React.ComponentProps; -import { Card as BaseCard } from '@/components/ui/card'; -type CardProps = React.ComponentProps; -import { Tabs, TabsTrigger as Tab, TabsList } from '@/components/ui/tabs'; -type TabsProps = React.ComponentProps; import { Accordion, AccordionItem, AccordionContent, AccordionTrigger, -} from '@/components/ui/accordion'; -type AccordionProps = React.ComponentProps; -import { Badge as Chip } from '@/components/ui/badge'; -type ChipProps = React.ComponentProps; - -import Link from 'next/link'; +} from "@/components/ui/accordion"; +import { Badge as Chip } from "@/components/ui/badge"; +import { Button, buttonVariants } from "@/components/ui/button"; +import { Card as BaseCard } from "@/components/ui/card"; +import { Tabs, TabsTrigger as Tab, TabsList } from "@/components/ui/tabs"; +// import { PiCheckCircleDuotone } from 'react-icons/pi'; +import { cn } from "@/lib/utils"; +import { ChevronRight as MdChevronRight } from "lucide-react"; +import { CheckCircle as PiCheckCircleDuotone } from "lucide-react"; +import Link from "next/link"; import type { HTMLAttributeAnchorTarget, HTMLAttributes, ReactNode, -} from 'react'; -import { twMerge } from 'tailwind-merge'; -import { ChevronRight as MdChevronRight} from 'lucide-react' +} from "react"; // import { MdChevronRight } from 'react-icons/md'; -import React from 'react'; -import { CheckCircle as PiCheckCircleDuotone } from 'lucide-react' -// import { PiCheckCircleDuotone } from 'react-icons/pi'; -import { cn } from '@/lib/utils'; +import React from "react"; +import { twMerge } from "tailwind-merge"; + +type ButtonProps = React.ComponentProps; +type LinkProps = React.ComponentProps; + +type CardProps = React.ComponentProps; + +type TabsProps = React.ComponentProps; + +type AccordionProps = React.ComponentProps; + +type ChipProps = React.ComponentProps; function Section({ className, @@ -41,8 +45,8 @@ function Section({ return (
    @@ -64,12 +68,12 @@ function Title({

    {children} @@ -86,12 +90,12 @@ function Subtitle({

    {children} @@ -103,7 +107,7 @@ function Announcement({ className, children, href, - target = '_blank', + target = "_blank", ...props }: ChipProps & { href?: string; //string | UrlObject; @@ -112,8 +116,8 @@ function Announcement({ return ( {children} - {' '} + {" "} @@ -186,8 +190,8 @@ function PrimaryAction({ buttonVariants({ variant: variant, }), - 'group', - className, + "group", + className )} {...props} > @@ -206,17 +210,17 @@ function SecondaryAction({ hideArrow, ...props }: ActionLinkProps | ActionProps) { - if (props.be === 'button') { + if (props.be === "button") { return ( + + + } + data={{ + id: deployment.id, + description: deployment.description, + showcase_media: deployment.showcase_media ?? [], + }} + title="Share Page" + description="Edit share page details." + serverAction={updateSharePageInfo} + formSchema={publicShareDeployment} + /> + + ); +} diff --git a/web/src/components/VersionSelect.tsx b/web/src/components/VersionSelect.tsx index c37e521..b1067d7 100644 --- a/web/src/components/VersionSelect.tsx +++ b/web/src/components/VersionSelect.tsx @@ -39,7 +39,7 @@ import { TableHeader, TableRow, } from "@/components/ui/table"; -import type { workflowAPINodeType } from "@/db/schema"; +import type { showcaseMediaNullable, workflowAPINodeType } from "@/db/schema"; import { checkStatus, createRun } from "@/server/createRun"; import { createDeployments } from "@/server/curdDeploments"; import type { getMachines } from "@/server/curdMachine"; @@ -154,7 +154,9 @@ export const publicRunStore = create((set) => ({ setStatus: (status) => set({ status }), })); -export function PublicRunOutputs() { +export function PublicRunOutputs(props: { + preview: z.infer; +}) { const { image, loading, runId, status, setStatus, setImage, setLoading } = publicRunStore(); @@ -176,6 +178,15 @@ export function PublicRunOutputs() { return (
    + {!loading && !image && props.preview && props.preview.length > 0 && ( + <> + Generated image + + )} {!loading && image && ( void; + error: Error & { digest?: string }; + reset: () => void; }) { useEffect(() => { - // Log the error to an error reporting service - console.log(error?.message); + console.log(error.message); }, [error]); return ( @@ -26,9 +25,14 @@ export default function ErrorPage({
    Unexpected error.
    -
    Error: {error?.message}
    +
    Error: {error.message}
    -
    @@ -39,14 +43,20 @@ export default function ErrorPage({ ); } -export function ErrorFullPage() { +export function ErrorFullPage({ + error, + reset, +}: { + error: Error & { digest?: string }; + reset: () => void; +}) { return (
    - +
    ); } diff --git a/web/src/components/ui/auto-form/utils.ts b/web/src/components/ui/auto-form/utils.ts index 517447a..a69761a 100644 --- a/web/src/components/ui/auto-form/utils.ts +++ b/web/src/components/ui/auto-form/utils.ts @@ -1,5 +1,5 @@ -import { DefaultValues } from "react-hook-form"; -import { z } from "zod"; +import type { DefaultValues } from "react-hook-form"; +import type { z } from "zod"; // TODO: This should support recursive ZodEffects but TypeScript doesn't allow circular type definitions. export type ZodObjectOrWrapped = @@ -21,7 +21,7 @@ export function beautifyObjectName(string: string) { * This will unpack optionals, refinements, etc. */ export function getBaseSchema< - ChildType extends z.ZodAny | z.AnyZodObject = z.ZodAny, + ChildType extends z.ZodAny | z.AnyZodObject = z.ZodAny >(schema: ChildType | z.ZodEffects): ChildType { if ("innerType" in schema._def) { return getBaseSchema(schema._def.innerType as ChildType); @@ -54,12 +54,12 @@ export function getDefaultValueInZodStack(schema: z.ZodAny): any { if ("innerType" in typedSchema._def) { return getDefaultValueInZodStack( - typedSchema._def.innerType as unknown as z.ZodAny, + typedSchema._def.innerType as unknown as z.ZodAny ); } if ("schema" in typedSchema._def) { return getDefaultValueInZodStack( - (typedSchema._def as any).schema as z.ZodAny, + (typedSchema._def as any).schema as z.ZodAny ); } return undefined; @@ -69,7 +69,7 @@ export function getDefaultValueInZodStack(schema: z.ZodAny): any { * Get all default values from a Zod schema. */ export function getDefaultValues>( - schema: Schema, + schema: Schema ) { const { shape } = schema; type DefaultValuesType = DefaultValues>>; @@ -80,7 +80,7 @@ export function getDefaultValues>( if (getBaseType(item) === "ZodObject") { const defaultItems = getDefaultValues( - getBaseSchema(item) as unknown as z.ZodObject, + getBaseSchema(item) as unknown as z.ZodObject ); for (const defaultItemKey of Object.keys(defaultItems)) { const pathKey = `${key}.${defaultItemKey}` as keyof DefaultValuesType; @@ -98,7 +98,7 @@ export function getDefaultValues>( } export function getObjectFormSchema( - schema: ZodObjectOrWrapped, + schema: ZodObjectOrWrapped ): z.ZodObject { if (schema._def.typeName === "ZodEffects") { const typedSchema = schema as z.ZodEffects>; @@ -116,7 +116,7 @@ export function zodToHtmlInputProps( | z.ZodNumber | z.ZodString | z.ZodOptional - | any, + | any ): React.InputHTMLAttributes { if (["ZodOptional", "ZodNullable"].includes(schema._def.typeName)) { const typedSchema = schema as z.ZodOptional; @@ -128,9 +128,10 @@ export function zodToHtmlInputProps( const typedSchema = schema as z.ZodNumber | z.ZodString; - if (!("checks" in typedSchema._def)) return { - required: true - }; + if (!("checks" in typedSchema._def)) + return { + required: true, + }; const { checks } = typedSchema._def; const inputProps: React.InputHTMLAttributes = { diff --git a/web/src/components/ui/carousel.tsx b/web/src/components/ui/carousel.tsx new file mode 100644 index 0000000..ec505d0 --- /dev/null +++ b/web/src/components/ui/carousel.tsx @@ -0,0 +1,262 @@ +"use client" + +import * as React from "react" +import useEmblaCarousel, { + type UseEmblaCarouselType, +} from "embla-carousel-react" +import { ArrowLeft, ArrowRight } from "lucide-react" + +import { cn } from "@/lib/utils" +import { Button } from "@/components/ui/button" + +type CarouselApi = UseEmblaCarouselType[1] +type UseCarouselParameters = Parameters +type CarouselOptions = UseCarouselParameters[0] +type CarouselPlugin = UseCarouselParameters[1] + +type CarouselProps = { + opts?: CarouselOptions + plugins?: CarouselPlugin + orientation?: "horizontal" | "vertical" + setApi?: (api: CarouselApi) => void +} + +type CarouselContextProps = { + carouselRef: ReturnType[0] + api: ReturnType[1] + scrollPrev: () => void + scrollNext: () => void + canScrollPrev: boolean + canScrollNext: boolean +} & CarouselProps + +const CarouselContext = React.createContext(null) + +function useCarousel() { + const context = React.useContext(CarouselContext) + + if (!context) { + throw new Error("useCarousel must be used within a ") + } + + return context +} + +const Carousel = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes & CarouselProps +>( + ( + { + orientation = "horizontal", + opts, + setApi, + plugins, + className, + children, + ...props + }, + ref + ) => { + const [carouselRef, api] = useEmblaCarousel( + { + ...opts, + axis: orientation === "horizontal" ? "x" : "y", + }, + plugins + ) + const [canScrollPrev, setCanScrollPrev] = React.useState(false) + const [canScrollNext, setCanScrollNext] = React.useState(false) + + const onSelect = React.useCallback((api: CarouselApi) => { + if (!api) { + return + } + + setCanScrollPrev(api.canScrollPrev()) + setCanScrollNext(api.canScrollNext()) + }, []) + + const scrollPrev = React.useCallback(() => { + api?.scrollPrev() + }, [api]) + + const scrollNext = React.useCallback(() => { + api?.scrollNext() + }, [api]) + + const handleKeyDown = React.useCallback( + (event: React.KeyboardEvent) => { + if (event.key === "ArrowLeft") { + event.preventDefault() + scrollPrev() + } else if (event.key === "ArrowRight") { + event.preventDefault() + scrollNext() + } + }, + [scrollPrev, scrollNext] + ) + + React.useEffect(() => { + if (!api || !setApi) { + return + } + + setApi(api) + }, [api, setApi]) + + React.useEffect(() => { + if (!api) { + return + } + + onSelect(api) + api.on("reInit", onSelect) + api.on("select", onSelect) + + return () => { + api?.off("select", onSelect) + } + }, [api, onSelect]) + + return ( + +
    + {children} +
    +
    + ) + } +) +Carousel.displayName = "Carousel" + +const CarouselContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => { + const { carouselRef, orientation } = useCarousel() + + return ( +
    +
    +
    + ) +}) +CarouselContent.displayName = "CarouselContent" + +const CarouselItem = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => { + const { orientation } = useCarousel() + + return ( +
    + ) +}) +CarouselItem.displayName = "CarouselItem" + +const CarouselPrevious = React.forwardRef< + HTMLButtonElement, + React.ComponentProps +>(({ className, variant = "outline", size = "icon", ...props }, ref) => { + const { orientation, scrollPrev, canScrollPrev } = useCarousel() + + return ( + + ) +}) +CarouselPrevious.displayName = "CarouselPrevious" + +const CarouselNext = React.forwardRef< + HTMLButtonElement, + React.ComponentProps +>(({ className, variant = "outline", size = "icon", ...props }, ref) => { + const { orientation, scrollNext, canScrollNext } = useCarousel() + + return ( + + ) +}) +CarouselNext.displayName = "CarouselNext" + +export { + type CarouselApi, + Carousel, + CarouselContent, + CarouselItem, + CarouselPrevious, + CarouselNext, +} diff --git a/web/src/components/useServerActionData.tsx b/web/src/components/useServerActionData.tsx new file mode 100644 index 0000000..4e57b79 --- /dev/null +++ b/web/src/components/useServerActionData.tsx @@ -0,0 +1,26 @@ +"use client"; + +import { callServerPromise } from "@/components/callServerPromise"; +import { useEffect, useState, useTransition } from "react"; + +export function useServerActionData( + action: (data: I) => Promise, + input: I +) { + const [data, setData] = useState(null); + const [pending, startTransition] = useTransition(); + const [started, setStarted] = useState(false); + + useEffect(() => { + startTransition(() => { + setStarted(true); + callServerPromise(action(input)).then(setData); + }); + }, [action, input]); + + return { + started, + data, + pending, + }; +} diff --git a/web/src/db/schema.ts b/web/src/db/schema.ts index 0cc2678..f5f8fdf 100644 --- a/web/src/db/schema.ts +++ b/web/src/db/schema.ts @@ -239,6 +239,22 @@ export const insertMachineSchema = createInsertSchema(machinesTable, { type: (schema) => schema.type.default("classic"), }); +export const showcaseMedia = z.array( + z.object({ + url: z.string(), + isCover: z.boolean().default(false), + }) +); + +export const showcaseMediaNullable = z + .array( + z.object({ + url: z.string(), + isCover: z.boolean().default(false), + }) + ) + .nullable(); + export const deploymentsTable = dbSchema.table("deployments", { id: uuid("id").primaryKey().defaultRandom().notNull(), user_id: text("user_id") @@ -246,6 +262,7 @@ export const deploymentsTable = dbSchema.table("deployments", { onDelete: "cascade", }) .notNull(), + org_id: text("org_id"), workflow_version_id: uuid("workflow_version_id") .notNull() .references(() => workflowVersionTable.id), @@ -257,11 +274,27 @@ export const deploymentsTable = dbSchema.table("deployments", { machine_id: uuid("machine_id") .notNull() .references(() => machinesTable.id), + description: text("description"), + showcase_media: + jsonb("showcase_media").$type>(), environment: deploymentEnvironment("environment").notNull(), created_at: timestamp("created_at").defaultNow().notNull(), updated_at: timestamp("updated_at").defaultNow().notNull(), }); +export const publicShareDeployment = z.object({ + description: z.string().nullable(), + showcase_media: showcaseMedia, +}); + +// createInsertSchema(deploymentsTable, { +// description: (schema) => schema.description.default(""), +// showcase_media: () => showcaseMedia.default([]), +// }).pick({ +// description: true, +// showcase_media: true, +// }); + export const deploymentsRelations = relations(deploymentsTable, ({ one }) => ({ machine: one(machinesTable, { fields: [deploymentsTable.machine_id], diff --git a/web/src/server/curdDeploments.ts b/web/src/server/curdDeploments.ts index 4724f54..85270cf 100644 --- a/web/src/server/curdDeploments.ts +++ b/web/src/server/curdDeploments.ts @@ -1,7 +1,7 @@ "use server"; import { db } from "@/db/db"; -import type { DeploymentType } from "@/db/schema"; +import type { DeploymentType, publicShareDeployment } from "@/db/schema"; import { deploymentsTable, workflowTable } from "@/db/schema"; import { createNewWorkflow } from "@/server/createNewWorkflow"; import { addCustomMachine } from "@/server/curdMachine"; @@ -11,6 +11,7 @@ import { and, eq, isNull } from "drizzle-orm"; import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import "server-only"; +import type { z } from "zod"; export async function createDeployments( workflow_id: string, @@ -18,7 +19,7 @@ export async function createDeployments( machine_id: string, environment: DeploymentType["environment"] ) { - const { userId } = auth(); + const { userId, orgId } = auth(); if (!userId) throw new Error("No user id"); if (!machine_id) { @@ -40,6 +41,7 @@ export async function createDeployments( workflow_id, workflow_version_id: version_id, machine_id, + org_id: orgId, }) .where(eq(deploymentsTable.id, existingDeployment.id)); } else { @@ -49,6 +51,7 @@ export async function createDeployments( workflow_version_id: version_id, machine_id, environment, + org_id: orgId, }); } revalidatePath(`/${workflow_id}`); @@ -195,3 +198,56 @@ export const cloneMachine = withServerPromise(async (deployment_id: string) => { message: "Successfully cloned workflow", }; }); + +export async function findUserShareDeployment(share_id: string) { + const { userId, orgId } = auth(); + + if (!userId) throw new Error("No user id"); + + const [deployment] = await db + .select() + .from(deploymentsTable) + .where( + and( + eq(deploymentsTable.id, share_id), + eq(deploymentsTable.environment, "public-share"), + orgId + ? eq(deploymentsTable.org_id, orgId) + : and( + eq(deploymentsTable.user_id, userId), + isNull(deploymentsTable.org_id) + ) + ) + ); + + if (!deployment) throw new Error("No deployment found"); + + return deployment; +} + +export const updateSharePageInfo = withServerPromise( + async ({ + id, + ...data + }: z.infer & { + id: string; + }) => { + const { userId } = auth(); + if (!userId) return { error: "No user id" }; + + console.log(data); + + const [deployment] = await db + .update(deploymentsTable) + .set(data) + .where( + and( + eq(deploymentsTable.environment, "public-share"), + eq(deploymentsTable.id, id) + ) + ) + .returning(); + + return { message: "Info Updated" }; + } +);