From 30ec7d3105cb74cadaa8157b980a2c300f774300 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 551063 -> 552354 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 | 3 + 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, 2394 insertions(+), 250 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 8ca5312d2ecdb940fdcb89f9404a6c3eadce43d7..25e42d7a554e5a82e4ccce7aa5ee52d9c7b28c01 100755 GIT binary patch delta 99818 zcmeF4d3aPsyY0Ih8nQ(MQGrAOK}1mFgxY~Xnn4rqGF;rfQpJ+ zErMTE6a`eA2T)N#K~QlX2pSPbP!VTAMelFzs*cga@%hfV-*f-D^h2_0t$M5Kt*W7!D3M3 zGp0!>lnkB$9tyq)NFh3N^wrQ>xEeSP?^S+^hLcYU9N)?xAfG?ww>!H9;C{y8FR%MqQZd*L9wVm{w!qS4AlCgO?Qzryg6KPX1w}Oz8 zXIHkd_ztKcDxNVlup57b?dnqOWPkmU*2hag@eb|mkj=Cs8Y;Etf+e;R zu9>;5y$!8-pt@0*YV~Y?QQc-`7olp%iX4syRqNQIqDlF=p->+QLMx}l4aV3!!k=j{a7EGFPIhpng9pLeb+&d>Sp)hk_8*KkD;rI1 za-y(kTyAR4nEc}0g6X-`azq!~N@>pI$@#@4p)06Wof;3Swqc+;+YeNE_PT;8`6Zzr zj<>B&%_$g{Lo3_h@_liJwfj1OM+K`rrMxK)G{xY}xHWu-49(SKKc`-^vd0)ZE#hf~ zQ*&le-Dd~;>c6Up|OJ2`i3$zXKVx59tDezUTPgDvantV>*Q zP0bxQZ6@v47| z3D_RQ{><`shS}*~10GDq%#vKLnW50#a5a2`%byDdamET%JWX+qOfH%cTvlH5A53bN ze>m>S>f{lj5F23mfv#KM(=GAMpxoFw(spMZT&*qy<$iFDPR%dAB-^@wKYBCtRikXT znxAV2d9i<@*Q&`pa<%=G*o7GKa{Mvgajlz-v6a6*+TwF?IrS9$5b#|8L9bQo%yG6O z6N`%q$LCMZ?FUz7i?LG2EBtT0X5OQ@){!~>f%~ydPq3rSr7m^+={5*|n3idJ3$YGThP;??7~9gYYJuutSppIk&`<8sfNmV*<8 zXTx;74fm}dFAVBjEl zIQfZykI)k}@Hsu#g6MFe&2Ipz18dQ>kv#=!s&d8_O(hvh=hp%7doSY5)Re^eGxE7G zheAE^MxK2So(O(W*A8V_)nRl(VD+M)5Bd@c1He928I;i@O0$YVbS>-Rzx5L)+dRt&>Zb8n}Nuf|a z-fGyhz(!y%P{aC@ZzRc^Y&6k5|<73R)lWa-Myc5Z%OXvg>y zP|^7^$efjxKT1OVz1d}40%|e}K{YTOYzhtlJ#gGD*1=wIE%3zIx)WUUGiF-xn4;29 z==odSd^x?DD_@Xb5;)cfM;nC3av>q19{-yj|Jx2H9BSr2*yt!P?=IWTOn+;mW*rWJ z$=Rf(cCNLzx$aQV3pxex{w<9l#G<^F#3Tm7&dmU|zubIx5<&g7i3ak;l5sE1d92ZMKD z*bP9b1(~YOi;)=!wnz4eT@@>l}W&(ybw|5!+h%DWfy60P>$sl6&5LDB@L-VH?6Wg{TWn!ccJeG z&IQ%pH%}Awn#+$!9N-_>l^}#+j zw)~7b*5$d+*-1VdgJcZ4fSQZPUbK_m4z2}#FsQlPjlE*N+Le0>RB&v3*{+G{@PpuY zKIdm0lu`EGtG4(Db*z7Pyk?ty0WSX%H{-)!xBcx6sy`1o`zzkC&E4$m&wkU!Xm7?x zb_uut-W}K9vP6gf+kRzGq53!WT|1zCLG{0*!#kg|j<$qrfRjMkx2duYTm))d3P4Rv zVw~)_a5DM(z+6U8RKaQe`2x)Yf) zt*~?~x0lahpaRQ4t-6JvR&7I2Lwh?FsiDNi_rw>r;*y*xIb$a0hT4&@4kd%?&~KmE z4K;UqZea=Sd;{NKhs5{3vORqRRDlHFih&w@9aK;~1FGSrU^DO

#*sX=A$(R4k-? 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 !@>gCA2 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%0D^699jV5 zYzBw6QtKVC`Q+U;jU60EC(c-isrhv!B2~uncjvF}yVt?+N+la>dQ>UrT}v59NXkhP z#<*D~>55$#-mYTcjPtu396<HvtC?b3Dc^^Pb#y zYdAQ1PLgAkJ_;PnT<4aHKAxVusjP!zu1dFchIh%*__)7tgshz;Sz-`3R;542^`{Ok z(iZFI;5en?PA&c*TgM5r$2danPLj@uYk#Xa_PvPm8MLGxj@mPHPZKQ*!Qq`XTCbBK zp@)8pnX-O>gF{~=ws?y?ia~dhV96EbI1@clN-RQRKPV%6zIhW^`#?yzCQ9SjJW;xX zBjhMJXv%+*cE2JL9HAR@itVHkDXj$kqi{<{&E?M}kGCg#=BK zl#8KR1;nNKS5}N@*0Xf3xsJF^CP^7^g!EK~%9Ad4LG!p9F%FLZudl0*sj3X)_a5x! z;u?ZbnloaIQp1SPdl4re8;T*NMR)1Ev;5c?gwl-Z1}4%Zbt9?ic+3@g@m?+pat{}{ zK+a7W)gS3>GN#MVHlvkv%PefB;_rFSX|(y;U+13le4OX~cs}m?ocDQ^Lnpa^-bj0y zRyQU4sj2D@ckcL!Nm}L5N!pP{y3CUOY|@_o@zb`L8HINyY5!@YC=a+#!vJxg*`jlj z`mOuVOkya9PI7hg7w4U93=T}P z$N_}In7WrdSAKK9>5xs}l5Lh{9vbuE^-f^0-Cs9)tJt-8GkgXb37=rGn6EWOKKTEF zvP|~fUc*D3yX_d-mbry3Gg2??T?i0f?r*tSomAzzy$cZbJCNf)XZvQ8fU3O%47*a*B!<#TN(iiEC(|lbO=2jmq=djq-ebv>swOd@YAGGy zu2eONp|p|`0xP+lX_cxbF+!cjSh@xp-XESBJ{_Zvg=(G`seU@sAr591=tf*JH959+ z=_@517o{fiO15P=AUuPQ+{@1&+B2<^V;ULspx`3*fa17`jl;!s`gplVz>v@1NdhH9Ql+AO)s{Z{pW zaNzhsTJm#)F<}XSu!in!v_6`m? zaahdCrAAdyEGO|ZS(FsN9Wc7G)}<_G-Gx!U6w!?}xk#Fa zOTHD8iihEnv&QpQd;Bv`;-2SO-3({sL~O>@nYiIj{%XP7CAnL&FRaWna>Nbo6Z;33 zyjxgGdzf1(9qksm+MhY}OSgzi*ol7@JcQca?ZH{!Mt!{x_iVLm$0Ne(w_ez|vz}h; z5pmj>pNepuHRd;R0Bya)w~DfgcG$X%R!o%keb^)XQ~DMU2vmH1d7;hL=dB9A|Mx>W CLQ-Y` 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 290c261..e717527 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 ae372fe..bc6aef4 100644 --- a/web/src/app/(app)/layout.tsx +++ b/web/src/app/(app)/layout.tsx @@ -27,8 +27,10 @@ export const metadata: Metadata = { export default function RootLayout({ children, + modal, }: { children: React.ReactNode; + modal: React.ReactNode; }) { return ( @@ -51,6 +53,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({ +

- + 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 - - -
- - 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" }; + } +);