feat: add public share options for workflow
This commit is contained in:
		
							parent
							
								
									dafc8b168b
								
							
						
					
					
						commit
						18cfbce171
					
				
							
								
								
									
										1
									
								
								web/drizzle/0027_eminent_lilith.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								web/drizzle/0027_eminent_lilith.sql
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					ALTER TYPE "deployment_environment" ADD VALUE 'public-share';
 | 
				
			||||||
							
								
								
									
										737
									
								
								web/drizzle/meta/0027_snapshot.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										737
									
								
								web/drizzle/meta/0027_snapshot.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,737 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "id": "dddfedc3-5b2f-4d54-a996-821945b9ff80",
 | 
				
			||||||
 | 
					  "prevId": "9d175095-5a2f-45b8-a38f-2a5f01f93a31",
 | 
				
			||||||
 | 
					  "version": "5",
 | 
				
			||||||
 | 
					  "dialect": "pg",
 | 
				
			||||||
 | 
					  "tables": {
 | 
				
			||||||
 | 
					    "api_keys": {
 | 
				
			||||||
 | 
					      "name": "api_keys",
 | 
				
			||||||
 | 
					      "schema": "comfyui_deploy",
 | 
				
			||||||
 | 
					      "columns": {
 | 
				
			||||||
 | 
					        "id": {
 | 
				
			||||||
 | 
					          "name": "id",
 | 
				
			||||||
 | 
					          "type": "uuid",
 | 
				
			||||||
 | 
					          "primaryKey": true,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "gen_random_uuid()"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "key": {
 | 
				
			||||||
 | 
					          "name": "key",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "name": {
 | 
				
			||||||
 | 
					          "name": "name",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "user_id": {
 | 
				
			||||||
 | 
					          "name": "user_id",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "org_id": {
 | 
				
			||||||
 | 
					          "name": "org_id",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "revoked": {
 | 
				
			||||||
 | 
					          "name": "revoked",
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "created_at": {
 | 
				
			||||||
 | 
					          "name": "created_at",
 | 
				
			||||||
 | 
					          "type": "timestamp",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "now()"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "updated_at": {
 | 
				
			||||||
 | 
					          "name": "updated_at",
 | 
				
			||||||
 | 
					          "type": "timestamp",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "now()"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "indexes": {},
 | 
				
			||||||
 | 
					      "foreignKeys": {
 | 
				
			||||||
 | 
					        "api_keys_user_id_users_id_fk": {
 | 
				
			||||||
 | 
					          "name": "api_keys_user_id_users_id_fk",
 | 
				
			||||||
 | 
					          "tableFrom": "api_keys",
 | 
				
			||||||
 | 
					          "tableTo": "users",
 | 
				
			||||||
 | 
					          "columnsFrom": [
 | 
				
			||||||
 | 
					            "user_id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "columnsTo": [
 | 
				
			||||||
 | 
					            "id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "onDelete": "cascade",
 | 
				
			||||||
 | 
					          "onUpdate": "no action"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "compositePrimaryKeys": {},
 | 
				
			||||||
 | 
					      "uniqueConstraints": {
 | 
				
			||||||
 | 
					        "api_keys_key_unique": {
 | 
				
			||||||
 | 
					          "name": "api_keys_key_unique",
 | 
				
			||||||
 | 
					          "nullsNotDistinct": false,
 | 
				
			||||||
 | 
					          "columns": [
 | 
				
			||||||
 | 
					            "key"
 | 
				
			||||||
 | 
					          ]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "deployments": {
 | 
				
			||||||
 | 
					      "name": "deployments",
 | 
				
			||||||
 | 
					      "schema": "comfyui_deploy",
 | 
				
			||||||
 | 
					      "columns": {
 | 
				
			||||||
 | 
					        "id": {
 | 
				
			||||||
 | 
					          "name": "id",
 | 
				
			||||||
 | 
					          "type": "uuid",
 | 
				
			||||||
 | 
					          "primaryKey": true,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "gen_random_uuid()"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "user_id": {
 | 
				
			||||||
 | 
					          "name": "user_id",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "workflow_version_id": {
 | 
				
			||||||
 | 
					          "name": "workflow_version_id",
 | 
				
			||||||
 | 
					          "type": "uuid",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "workflow_id": {
 | 
				
			||||||
 | 
					          "name": "workflow_id",
 | 
				
			||||||
 | 
					          "type": "uuid",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "machine_id": {
 | 
				
			||||||
 | 
					          "name": "machine_id",
 | 
				
			||||||
 | 
					          "type": "uuid",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "environment": {
 | 
				
			||||||
 | 
					          "name": "environment",
 | 
				
			||||||
 | 
					          "type": "deployment_environment",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "created_at": {
 | 
				
			||||||
 | 
					          "name": "created_at",
 | 
				
			||||||
 | 
					          "type": "timestamp",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "now()"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "updated_at": {
 | 
				
			||||||
 | 
					          "name": "updated_at",
 | 
				
			||||||
 | 
					          "type": "timestamp",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "now()"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "indexes": {},
 | 
				
			||||||
 | 
					      "foreignKeys": {
 | 
				
			||||||
 | 
					        "deployments_user_id_users_id_fk": {
 | 
				
			||||||
 | 
					          "name": "deployments_user_id_users_id_fk",
 | 
				
			||||||
 | 
					          "tableFrom": "deployments",
 | 
				
			||||||
 | 
					          "tableTo": "users",
 | 
				
			||||||
 | 
					          "columnsFrom": [
 | 
				
			||||||
 | 
					            "user_id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "columnsTo": [
 | 
				
			||||||
 | 
					            "id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "onDelete": "cascade",
 | 
				
			||||||
 | 
					          "onUpdate": "no action"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "deployments_workflow_version_id_workflow_versions_id_fk": {
 | 
				
			||||||
 | 
					          "name": "deployments_workflow_version_id_workflow_versions_id_fk",
 | 
				
			||||||
 | 
					          "tableFrom": "deployments",
 | 
				
			||||||
 | 
					          "tableTo": "workflow_versions",
 | 
				
			||||||
 | 
					          "columnsFrom": [
 | 
				
			||||||
 | 
					            "workflow_version_id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "columnsTo": [
 | 
				
			||||||
 | 
					            "id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "onDelete": "no action",
 | 
				
			||||||
 | 
					          "onUpdate": "no action"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "deployments_workflow_id_workflows_id_fk": {
 | 
				
			||||||
 | 
					          "name": "deployments_workflow_id_workflows_id_fk",
 | 
				
			||||||
 | 
					          "tableFrom": "deployments",
 | 
				
			||||||
 | 
					          "tableTo": "workflows",
 | 
				
			||||||
 | 
					          "columnsFrom": [
 | 
				
			||||||
 | 
					            "workflow_id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "columnsTo": [
 | 
				
			||||||
 | 
					            "id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "onDelete": "cascade",
 | 
				
			||||||
 | 
					          "onUpdate": "no action"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "deployments_machine_id_machines_id_fk": {
 | 
				
			||||||
 | 
					          "name": "deployments_machine_id_machines_id_fk",
 | 
				
			||||||
 | 
					          "tableFrom": "deployments",
 | 
				
			||||||
 | 
					          "tableTo": "machines",
 | 
				
			||||||
 | 
					          "columnsFrom": [
 | 
				
			||||||
 | 
					            "machine_id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "columnsTo": [
 | 
				
			||||||
 | 
					            "id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "onDelete": "no action",
 | 
				
			||||||
 | 
					          "onUpdate": "no action"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "compositePrimaryKeys": {},
 | 
				
			||||||
 | 
					      "uniqueConstraints": {}
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "machines": {
 | 
				
			||||||
 | 
					      "name": "machines",
 | 
				
			||||||
 | 
					      "schema": "comfyui_deploy",
 | 
				
			||||||
 | 
					      "columns": {
 | 
				
			||||||
 | 
					        "id": {
 | 
				
			||||||
 | 
					          "name": "id",
 | 
				
			||||||
 | 
					          "type": "uuid",
 | 
				
			||||||
 | 
					          "primaryKey": true,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "gen_random_uuid()"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "user_id": {
 | 
				
			||||||
 | 
					          "name": "user_id",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "name": {
 | 
				
			||||||
 | 
					          "name": "name",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "org_id": {
 | 
				
			||||||
 | 
					          "name": "org_id",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "endpoint": {
 | 
				
			||||||
 | 
					          "name": "endpoint",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "created_at": {
 | 
				
			||||||
 | 
					          "name": "created_at",
 | 
				
			||||||
 | 
					          "type": "timestamp",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "now()"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "updated_at": {
 | 
				
			||||||
 | 
					          "name": "updated_at",
 | 
				
			||||||
 | 
					          "type": "timestamp",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "now()"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "disabled": {
 | 
				
			||||||
 | 
					          "name": "disabled",
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "auth_token": {
 | 
				
			||||||
 | 
					          "name": "auth_token",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "type": {
 | 
				
			||||||
 | 
					          "name": "type",
 | 
				
			||||||
 | 
					          "type": "machine_type",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "'classic'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "status": {
 | 
				
			||||||
 | 
					          "name": "status",
 | 
				
			||||||
 | 
					          "type": "machine_status",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "'ready'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "snapshot": {
 | 
				
			||||||
 | 
					          "name": "snapshot",
 | 
				
			||||||
 | 
					          "type": "jsonb",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "models": {
 | 
				
			||||||
 | 
					          "name": "models",
 | 
				
			||||||
 | 
					          "type": "jsonb",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "gpu": {
 | 
				
			||||||
 | 
					          "name": "gpu",
 | 
				
			||||||
 | 
					          "type": "machine_gpu",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "build_machine_instance_id": {
 | 
				
			||||||
 | 
					          "name": "build_machine_instance_id",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "build_log": {
 | 
				
			||||||
 | 
					          "name": "build_log",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "indexes": {},
 | 
				
			||||||
 | 
					      "foreignKeys": {
 | 
				
			||||||
 | 
					        "machines_user_id_users_id_fk": {
 | 
				
			||||||
 | 
					          "name": "machines_user_id_users_id_fk",
 | 
				
			||||||
 | 
					          "tableFrom": "machines",
 | 
				
			||||||
 | 
					          "tableTo": "users",
 | 
				
			||||||
 | 
					          "columnsFrom": [
 | 
				
			||||||
 | 
					            "user_id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "columnsTo": [
 | 
				
			||||||
 | 
					            "id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "onDelete": "cascade",
 | 
				
			||||||
 | 
					          "onUpdate": "no action"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "compositePrimaryKeys": {},
 | 
				
			||||||
 | 
					      "uniqueConstraints": {}
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "users": {
 | 
				
			||||||
 | 
					      "name": "users",
 | 
				
			||||||
 | 
					      "schema": "comfyui_deploy",
 | 
				
			||||||
 | 
					      "columns": {
 | 
				
			||||||
 | 
					        "id": {
 | 
				
			||||||
 | 
					          "name": "id",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": true,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "username": {
 | 
				
			||||||
 | 
					          "name": "username",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "name": {
 | 
				
			||||||
 | 
					          "name": "name",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "created_at": {
 | 
				
			||||||
 | 
					          "name": "created_at",
 | 
				
			||||||
 | 
					          "type": "timestamp",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false,
 | 
				
			||||||
 | 
					          "default": "now()"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "updated_at": {
 | 
				
			||||||
 | 
					          "name": "updated_at",
 | 
				
			||||||
 | 
					          "type": "timestamp",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false,
 | 
				
			||||||
 | 
					          "default": "now()"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "indexes": {},
 | 
				
			||||||
 | 
					      "foreignKeys": {},
 | 
				
			||||||
 | 
					      "compositePrimaryKeys": {},
 | 
				
			||||||
 | 
					      "uniqueConstraints": {}
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "workflow_run_outputs": {
 | 
				
			||||||
 | 
					      "name": "workflow_run_outputs",
 | 
				
			||||||
 | 
					      "schema": "comfyui_deploy",
 | 
				
			||||||
 | 
					      "columns": {
 | 
				
			||||||
 | 
					        "id": {
 | 
				
			||||||
 | 
					          "name": "id",
 | 
				
			||||||
 | 
					          "type": "uuid",
 | 
				
			||||||
 | 
					          "primaryKey": true,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "gen_random_uuid()"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "run_id": {
 | 
				
			||||||
 | 
					          "name": "run_id",
 | 
				
			||||||
 | 
					          "type": "uuid",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "data": {
 | 
				
			||||||
 | 
					          "name": "data",
 | 
				
			||||||
 | 
					          "type": "jsonb",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "created_at": {
 | 
				
			||||||
 | 
					          "name": "created_at",
 | 
				
			||||||
 | 
					          "type": "timestamp",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "now()"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "updated_at": {
 | 
				
			||||||
 | 
					          "name": "updated_at",
 | 
				
			||||||
 | 
					          "type": "timestamp",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "now()"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "indexes": {},
 | 
				
			||||||
 | 
					      "foreignKeys": {
 | 
				
			||||||
 | 
					        "workflow_run_outputs_run_id_workflow_runs_id_fk": {
 | 
				
			||||||
 | 
					          "name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
 | 
				
			||||||
 | 
					          "tableFrom": "workflow_run_outputs",
 | 
				
			||||||
 | 
					          "tableTo": "workflow_runs",
 | 
				
			||||||
 | 
					          "columnsFrom": [
 | 
				
			||||||
 | 
					            "run_id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "columnsTo": [
 | 
				
			||||||
 | 
					            "id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "onDelete": "cascade",
 | 
				
			||||||
 | 
					          "onUpdate": "no action"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "compositePrimaryKeys": {},
 | 
				
			||||||
 | 
					      "uniqueConstraints": {}
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "workflow_runs": {
 | 
				
			||||||
 | 
					      "name": "workflow_runs",
 | 
				
			||||||
 | 
					      "schema": "comfyui_deploy",
 | 
				
			||||||
 | 
					      "columns": {
 | 
				
			||||||
 | 
					        "id": {
 | 
				
			||||||
 | 
					          "name": "id",
 | 
				
			||||||
 | 
					          "type": "uuid",
 | 
				
			||||||
 | 
					          "primaryKey": true,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "gen_random_uuid()"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "workflow_version_id": {
 | 
				
			||||||
 | 
					          "name": "workflow_version_id",
 | 
				
			||||||
 | 
					          "type": "uuid",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "workflow_inputs": {
 | 
				
			||||||
 | 
					          "name": "workflow_inputs",
 | 
				
			||||||
 | 
					          "type": "jsonb",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "workflow_id": {
 | 
				
			||||||
 | 
					          "name": "workflow_id",
 | 
				
			||||||
 | 
					          "type": "uuid",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "machine_id": {
 | 
				
			||||||
 | 
					          "name": "machine_id",
 | 
				
			||||||
 | 
					          "type": "uuid",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "origin": {
 | 
				
			||||||
 | 
					          "name": "origin",
 | 
				
			||||||
 | 
					          "type": "workflow_run_origin",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "'api'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "status": {
 | 
				
			||||||
 | 
					          "name": "status",
 | 
				
			||||||
 | 
					          "type": "workflow_run_status",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "'not-started'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "ended_at": {
 | 
				
			||||||
 | 
					          "name": "ended_at",
 | 
				
			||||||
 | 
					          "type": "timestamp",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "created_at": {
 | 
				
			||||||
 | 
					          "name": "created_at",
 | 
				
			||||||
 | 
					          "type": "timestamp",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "now()"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "indexes": {},
 | 
				
			||||||
 | 
					      "foreignKeys": {
 | 
				
			||||||
 | 
					        "workflow_runs_workflow_version_id_workflow_versions_id_fk": {
 | 
				
			||||||
 | 
					          "name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
 | 
				
			||||||
 | 
					          "tableFrom": "workflow_runs",
 | 
				
			||||||
 | 
					          "tableTo": "workflow_versions",
 | 
				
			||||||
 | 
					          "columnsFrom": [
 | 
				
			||||||
 | 
					            "workflow_version_id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "columnsTo": [
 | 
				
			||||||
 | 
					            "id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "onDelete": "set null",
 | 
				
			||||||
 | 
					          "onUpdate": "no action"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "workflow_runs_workflow_id_workflows_id_fk": {
 | 
				
			||||||
 | 
					          "name": "workflow_runs_workflow_id_workflows_id_fk",
 | 
				
			||||||
 | 
					          "tableFrom": "workflow_runs",
 | 
				
			||||||
 | 
					          "tableTo": "workflows",
 | 
				
			||||||
 | 
					          "columnsFrom": [
 | 
				
			||||||
 | 
					            "workflow_id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "columnsTo": [
 | 
				
			||||||
 | 
					            "id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "onDelete": "cascade",
 | 
				
			||||||
 | 
					          "onUpdate": "no action"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "workflow_runs_machine_id_machines_id_fk": {
 | 
				
			||||||
 | 
					          "name": "workflow_runs_machine_id_machines_id_fk",
 | 
				
			||||||
 | 
					          "tableFrom": "workflow_runs",
 | 
				
			||||||
 | 
					          "tableTo": "machines",
 | 
				
			||||||
 | 
					          "columnsFrom": [
 | 
				
			||||||
 | 
					            "machine_id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "columnsTo": [
 | 
				
			||||||
 | 
					            "id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "onDelete": "set null",
 | 
				
			||||||
 | 
					          "onUpdate": "no action"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "compositePrimaryKeys": {},
 | 
				
			||||||
 | 
					      "uniqueConstraints": {}
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "workflows": {
 | 
				
			||||||
 | 
					      "name": "workflows",
 | 
				
			||||||
 | 
					      "schema": "comfyui_deploy",
 | 
				
			||||||
 | 
					      "columns": {
 | 
				
			||||||
 | 
					        "id": {
 | 
				
			||||||
 | 
					          "name": "id",
 | 
				
			||||||
 | 
					          "type": "uuid",
 | 
				
			||||||
 | 
					          "primaryKey": true,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "gen_random_uuid()"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "user_id": {
 | 
				
			||||||
 | 
					          "name": "user_id",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "org_id": {
 | 
				
			||||||
 | 
					          "name": "org_id",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "name": {
 | 
				
			||||||
 | 
					          "name": "name",
 | 
				
			||||||
 | 
					          "type": "text",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "created_at": {
 | 
				
			||||||
 | 
					          "name": "created_at",
 | 
				
			||||||
 | 
					          "type": "timestamp",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "now()"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "updated_at": {
 | 
				
			||||||
 | 
					          "name": "updated_at",
 | 
				
			||||||
 | 
					          "type": "timestamp",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "now()"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "indexes": {},
 | 
				
			||||||
 | 
					      "foreignKeys": {
 | 
				
			||||||
 | 
					        "workflows_user_id_users_id_fk": {
 | 
				
			||||||
 | 
					          "name": "workflows_user_id_users_id_fk",
 | 
				
			||||||
 | 
					          "tableFrom": "workflows",
 | 
				
			||||||
 | 
					          "tableTo": "users",
 | 
				
			||||||
 | 
					          "columnsFrom": [
 | 
				
			||||||
 | 
					            "user_id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "columnsTo": [
 | 
				
			||||||
 | 
					            "id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "onDelete": "cascade",
 | 
				
			||||||
 | 
					          "onUpdate": "no action"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "compositePrimaryKeys": {},
 | 
				
			||||||
 | 
					      "uniqueConstraints": {}
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "workflow_versions": {
 | 
				
			||||||
 | 
					      "name": "workflow_versions",
 | 
				
			||||||
 | 
					      "schema": "comfyui_deploy",
 | 
				
			||||||
 | 
					      "columns": {
 | 
				
			||||||
 | 
					        "workflow_id": {
 | 
				
			||||||
 | 
					          "name": "workflow_id",
 | 
				
			||||||
 | 
					          "type": "uuid",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "id": {
 | 
				
			||||||
 | 
					          "name": "id",
 | 
				
			||||||
 | 
					          "type": "uuid",
 | 
				
			||||||
 | 
					          "primaryKey": true,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "gen_random_uuid()"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "workflow": {
 | 
				
			||||||
 | 
					          "name": "workflow",
 | 
				
			||||||
 | 
					          "type": "jsonb",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "workflow_api": {
 | 
				
			||||||
 | 
					          "name": "workflow_api",
 | 
				
			||||||
 | 
					          "type": "jsonb",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "version": {
 | 
				
			||||||
 | 
					          "name": "version",
 | 
				
			||||||
 | 
					          "type": "integer",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "snapshot": {
 | 
				
			||||||
 | 
					          "name": "snapshot",
 | 
				
			||||||
 | 
					          "type": "jsonb",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "created_at": {
 | 
				
			||||||
 | 
					          "name": "created_at",
 | 
				
			||||||
 | 
					          "type": "timestamp",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "now()"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "updated_at": {
 | 
				
			||||||
 | 
					          "name": "updated_at",
 | 
				
			||||||
 | 
					          "type": "timestamp",
 | 
				
			||||||
 | 
					          "primaryKey": false,
 | 
				
			||||||
 | 
					          "notNull": true,
 | 
				
			||||||
 | 
					          "default": "now()"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "indexes": {},
 | 
				
			||||||
 | 
					      "foreignKeys": {
 | 
				
			||||||
 | 
					        "workflow_versions_workflow_id_workflows_id_fk": {
 | 
				
			||||||
 | 
					          "name": "workflow_versions_workflow_id_workflows_id_fk",
 | 
				
			||||||
 | 
					          "tableFrom": "workflow_versions",
 | 
				
			||||||
 | 
					          "tableTo": "workflows",
 | 
				
			||||||
 | 
					          "columnsFrom": [
 | 
				
			||||||
 | 
					            "workflow_id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "columnsTo": [
 | 
				
			||||||
 | 
					            "id"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "onDelete": "cascade",
 | 
				
			||||||
 | 
					          "onUpdate": "no action"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "compositePrimaryKeys": {},
 | 
				
			||||||
 | 
					      "uniqueConstraints": {}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "enums": {
 | 
				
			||||||
 | 
					    "deployment_environment": {
 | 
				
			||||||
 | 
					      "name": "deployment_environment",
 | 
				
			||||||
 | 
					      "values": {
 | 
				
			||||||
 | 
					        "staging": "staging",
 | 
				
			||||||
 | 
					        "production": "production",
 | 
				
			||||||
 | 
					        "public-share": "public-share"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "machine_gpu": {
 | 
				
			||||||
 | 
					      "name": "machine_gpu",
 | 
				
			||||||
 | 
					      "values": {
 | 
				
			||||||
 | 
					        "T4": "T4",
 | 
				
			||||||
 | 
					        "A10G": "A10G",
 | 
				
			||||||
 | 
					        "A100": "A100"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "machine_status": {
 | 
				
			||||||
 | 
					      "name": "machine_status",
 | 
				
			||||||
 | 
					      "values": {
 | 
				
			||||||
 | 
					        "ready": "ready",
 | 
				
			||||||
 | 
					        "building": "building",
 | 
				
			||||||
 | 
					        "error": "error"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "machine_type": {
 | 
				
			||||||
 | 
					      "name": "machine_type",
 | 
				
			||||||
 | 
					      "values": {
 | 
				
			||||||
 | 
					        "classic": "classic",
 | 
				
			||||||
 | 
					        "runpod-serverless": "runpod-serverless",
 | 
				
			||||||
 | 
					        "modal-serverless": "modal-serverless",
 | 
				
			||||||
 | 
					        "comfy-deploy-serverless": "comfy-deploy-serverless"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "workflow_run_origin": {
 | 
				
			||||||
 | 
					      "name": "workflow_run_origin",
 | 
				
			||||||
 | 
					      "values": {
 | 
				
			||||||
 | 
					        "manual": "manual",
 | 
				
			||||||
 | 
					        "api": "api"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "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": {}
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -190,6 +190,13 @@
 | 
				
			|||||||
      "when": 1704979846175,
 | 
					      "when": 1704979846175,
 | 
				
			||||||
      "tag": "0026_premium_rocket_raccoon",
 | 
					      "tag": "0026_premium_rocket_raccoon",
 | 
				
			||||||
      "breakpoints": true
 | 
					      "breakpoints": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "idx": 27,
 | 
				
			||||||
 | 
					      "version": "5",
 | 
				
			||||||
 | 
					      "when": 1705228261543,
 | 
				
			||||||
 | 
					      "tag": "0027_eminent_lilith",
 | 
				
			||||||
 | 
					      "breakpoints": true
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -3,9 +3,8 @@ import { db } from "@/db/db";
 | 
				
			|||||||
import { deploymentsTable, workflowRunsTable } from "@/db/schema";
 | 
					import { deploymentsTable, workflowRunsTable } from "@/db/schema";
 | 
				
			||||||
import { createSelectSchema } from "@/lib/drizzle-zod-hono";
 | 
					import { createSelectSchema } from "@/lib/drizzle-zod-hono";
 | 
				
			||||||
import { isKeyRevoked } from "@/server/curdApiKeys";
 | 
					import { isKeyRevoked } from "@/server/curdApiKeys";
 | 
				
			||||||
import { getRunsData } from "@/server/getRunsOutput";
 | 
					import { getRunsData } from "@/server/getRunsData";
 | 
				
			||||||
import { parseJWT } from "@/server/parseJWT";
 | 
					import { parseJWT } from "@/server/parseJWT";
 | 
				
			||||||
import { replaceCDNUrl } from "@/server/replaceCDNUrl";
 | 
					 | 
				
			||||||
import type { ResponseConfig } from "@asteasolutions/zod-to-openapi";
 | 
					import type { ResponseConfig } from "@asteasolutions/zod-to-openapi";
 | 
				
			||||||
import { z, createRoute } from "@hono/zod-openapi";
 | 
					import { z, createRoute } from "@hono/zod-openapi";
 | 
				
			||||||
import { OpenAPIHono } from "@hono/zod-openapi";
 | 
					import { OpenAPIHono } from "@hono/zod-openapi";
 | 
				
			||||||
@ -122,7 +121,7 @@ app.openapi(getOutputRoute, async (c) => {
 | 
				
			|||||||
  const apiKeyTokenData = c.get("apiKeyTokenData")!;
 | 
					  const apiKeyTokenData = c.get("apiKeyTokenData")!;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    const run = await getRunsData(apiKeyTokenData, data.run_id);
 | 
					    const run = await getRunsData(data.run_id, apiKeyTokenData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!run)
 | 
					    if (!run)
 | 
				
			||||||
      return c.json(
 | 
					      return c.json(
 | 
				
			||||||
@ -133,29 +132,6 @@ app.openapi(getOutputRoute, async (c) => {
 | 
				
			|||||||
        400
 | 
					        400
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Fill in the CDN url
 | 
					 | 
				
			||||||
    if (run?.status === "success" && run?.outputs?.length > 0) {
 | 
					 | 
				
			||||||
      for (let i = 0; i < run.outputs.length; i++) {
 | 
					 | 
				
			||||||
        const output = run.outputs[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (output.data?.images !== undefined) {
 | 
					 | 
				
			||||||
          for (let j = 0; j < output.data?.images.length; j++) {
 | 
					 | 
				
			||||||
            const element = output.data?.images[j];
 | 
					 | 
				
			||||||
            element.url = replaceCDNUrl(
 | 
					 | 
				
			||||||
              `${process.env.SPACES_ENDPOINT}/${process.env.SPACES_BUCKET}/outputs/runs/${run.id}/${element.filename}`
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        } else if (output.data?.files !== undefined) {
 | 
					 | 
				
			||||||
          for (let j = 0; j < output.data?.files.length; j++) {
 | 
					 | 
				
			||||||
            const element = output.data?.files[j];
 | 
					 | 
				
			||||||
            element.url = replaceCDNUrl(
 | 
					 | 
				
			||||||
              `${process.env.SPACES_ENDPOINT}/${process.env.SPACES_BUCKET}/outputs/runs/${run.id}/${element.filename}`
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return c.json(run, 200);
 | 
					    return c.json(run, 200);
 | 
				
			||||||
  } catch (error: any) {
 | 
					  } catch (error: any) {
 | 
				
			||||||
    return c.json(
 | 
					    return c.json(
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										9
									
								
								web/src/app/(app)/share/[share_id]/loading.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								web/src/app/(app)/share/[share_id]/loading.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					"use client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { LoadingPageWrapper } from "@/components/LoadingWrapper";
 | 
				
			||||||
 | 
					import { usePathname } from "next/navigation";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function Loading() {
 | 
				
			||||||
 | 
					  const pathName = usePathname();
 | 
				
			||||||
 | 
					  return <LoadingPageWrapper className="h-full" tag={pathName.toLowerCase()} />;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										87
									
								
								web/src/app/(app)/share/[share_id]/page.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								web/src/app/(app)/share/[share_id]/page.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,87 @@
 | 
				
			|||||||
 | 
					import {
 | 
				
			||||||
 | 
					  PublicRunOutputs,
 | 
				
			||||||
 | 
					  RunWorkflowInline,
 | 
				
			||||||
 | 
					} from "@/components/VersionSelect";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Card,
 | 
				
			||||||
 | 
					  CardContent,
 | 
				
			||||||
 | 
					  CardDescription,
 | 
				
			||||||
 | 
					  CardHeader,
 | 
				
			||||||
 | 
					  CardTitle,
 | 
				
			||||||
 | 
					} from "@/components/ui/card";
 | 
				
			||||||
 | 
					import { db } from "@/db/db";
 | 
				
			||||||
 | 
					import { usersTable } from "@/db/schema";
 | 
				
			||||||
 | 
					import { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow";
 | 
				
			||||||
 | 
					import { getRelativeTime } from "@/lib/getRelativeTime";
 | 
				
			||||||
 | 
					import { setInitialUserData } from "@/lib/setInitialUserData";
 | 
				
			||||||
 | 
					import { findSharedDeployment } from "@/server/curdDeploments";
 | 
				
			||||||
 | 
					import { auth, clerkClient } from "@clerk/nextjs/server";
 | 
				
			||||||
 | 
					import { eq } from "drizzle-orm";
 | 
				
			||||||
 | 
					import { redirect } from "next/navigation";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default async function Page({
 | 
				
			||||||
 | 
					  params,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  params: { share_id: string };
 | 
				
			||||||
 | 
					}) {
 | 
				
			||||||
 | 
					  const { userId } = await auth();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // If there is user, check if the user data is present
 | 
				
			||||||
 | 
					  if (userId) {
 | 
				
			||||||
 | 
					    const user = await db.query.usersTable.findFirst({
 | 
				
			||||||
 | 
					      where: eq(usersTable.id, userId),
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!user) {
 | 
				
			||||||
 | 
					      await setInitialUserData(userId);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const sharedDeployment = await findSharedDeployment(params.share_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!sharedDeployment) return redirect("/");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const userName = sharedDeployment.workflow.org_id
 | 
				
			||||||
 | 
					    ? await clerkClient.organizations
 | 
				
			||||||
 | 
					        .getOrganization({
 | 
				
			||||||
 | 
					          organizationId: sharedDeployment.workflow.org_id,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .then((x) => x.name)
 | 
				
			||||||
 | 
					    : sharedDeployment.user.name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const inputs = getInputsFromWorkflow(sharedDeployment.version);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="mt-4 w-full grid grid-rows-[1fr,1fr] lg:grid-cols-[minmax(auto,500px),1fr] gap-4 max-h-[calc(100dvh-100px)]">
 | 
				
			||||||
 | 
					      <Card className="w-full h-fit mt-4">
 | 
				
			||||||
 | 
					        <CardHeader>
 | 
				
			||||||
 | 
					          <CardTitle>
 | 
				
			||||||
 | 
					            {userName}
 | 
				
			||||||
 | 
					            {" / "}
 | 
				
			||||||
 | 
					            {sharedDeployment.workflow.name}
 | 
				
			||||||
 | 
					          </CardTitle>
 | 
				
			||||||
 | 
					          <CardDescription suppressHydrationWarning={true}>
 | 
				
			||||||
 | 
					            {getRelativeTime(sharedDeployment?.updated_at)}
 | 
				
			||||||
 | 
					          </CardDescription>
 | 
				
			||||||
 | 
					        </CardHeader>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <CardContent>
 | 
				
			||||||
 | 
					          <RunWorkflowInline
 | 
				
			||||||
 | 
					            inputs={inputs}
 | 
				
			||||||
 | 
					            machine_id={sharedDeployment.machine_id}
 | 
				
			||||||
 | 
					            workflow_version_id={sharedDeployment.workflow_version_id}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </CardContent>
 | 
				
			||||||
 | 
					      </Card>
 | 
				
			||||||
 | 
					      <Card className="w-full h-fit mt-4">
 | 
				
			||||||
 | 
					        <CardHeader>
 | 
				
			||||||
 | 
					          <CardDescription>Run outputs</CardDescription>
 | 
				
			||||||
 | 
					        </CardHeader>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <CardContent>
 | 
				
			||||||
 | 
					          <PublicRunOutputs />
 | 
				
			||||||
 | 
					        </CardContent>
 | 
				
			||||||
 | 
					      </Card>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -3,6 +3,7 @@ import { VersionDetails } from "@/components/VersionDetails";
 | 
				
			|||||||
import {
 | 
					import {
 | 
				
			||||||
  CopyWorkflowVersion,
 | 
					  CopyWorkflowVersion,
 | 
				
			||||||
  CreateDeploymentButton,
 | 
					  CreateDeploymentButton,
 | 
				
			||||||
 | 
					  CreateShareButton,
 | 
				
			||||||
  MachineSelect,
 | 
					  MachineSelect,
 | 
				
			||||||
  RunWorkflowButton,
 | 
					  RunWorkflowButton,
 | 
				
			||||||
  VersionSelect,
 | 
					  VersionSelect,
 | 
				
			||||||
@ -18,7 +19,6 @@ import {
 | 
				
			|||||||
import { getRelativeTime } from "@/lib/getRelativeTime";
 | 
					import { getRelativeTime } from "@/lib/getRelativeTime";
 | 
				
			||||||
import { getMachines } from "@/server/curdMachine";
 | 
					import { getMachines } from "@/server/curdMachine";
 | 
				
			||||||
import { findFirstTableWithVersion } from "@/server/findFirstTableWithVersion";
 | 
					import { findFirstTableWithVersion } from "@/server/findFirstTableWithVersion";
 | 
				
			||||||
import { redirect } from "next/navigation";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default async function Page({
 | 
					export default async function Page({
 | 
				
			||||||
  params,
 | 
					  params,
 | 
				
			||||||
@ -45,6 +45,7 @@ export default async function Page({
 | 
				
			|||||||
          <MachineSelect machines={machines} />
 | 
					          <MachineSelect machines={machines} />
 | 
				
			||||||
          <RunWorkflowButton workflow={workflow} machines={machines} />
 | 
					          <RunWorkflowButton workflow={workflow} machines={machines} />
 | 
				
			||||||
          <CreateDeploymentButton workflow={workflow} machines={machines} />
 | 
					          <CreateDeploymentButton workflow={workflow} machines={machines} />
 | 
				
			||||||
 | 
					          <CreateShareButton workflow={workflow} machines={machines} />
 | 
				
			||||||
          <CopyWorkflowVersion workflow={workflow} />
 | 
					          <CopyWorkflowVersion workflow={workflow} />
 | 
				
			||||||
          <ViewWorkflowDetailsButton workflow={workflow} />
 | 
					          <ViewWorkflowDetailsButton workflow={workflow} />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,8 @@
 | 
				
			|||||||
 | 
					import { setInitialUserData } from "../../../lib/setInitialUserData";
 | 
				
			||||||
import { WorkflowList } from "@/components/WorkflowList";
 | 
					import { WorkflowList } from "@/components/WorkflowList";
 | 
				
			||||||
import { db } from "@/db/db";
 | 
					import { db } from "@/db/db";
 | 
				
			||||||
import { usersTable, workflowTable, workflowVersionTable } from "@/db/schema";
 | 
					import { usersTable, workflowTable, workflowVersionTable } from "@/db/schema";
 | 
				
			||||||
import { auth, clerkClient } from "@clerk/nextjs";
 | 
					import { auth } from "@clerk/nextjs";
 | 
				
			||||||
import { and, desc, eq, isNull } from "drizzle-orm";
 | 
					import { and, desc, eq, isNull } from "drizzle-orm";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function Home() {
 | 
					export default function Home() {
 | 
				
			||||||
@ -55,26 +56,3 @@ async function WorkflowServer() {
 | 
				
			|||||||
    />
 | 
					    />
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
async function setInitialUserData(userId: string) {
 | 
					 | 
				
			||||||
  const user = await clerkClient.users.getUser(userId);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // incase we dont have username such as google login, fallback to first name + last name
 | 
					 | 
				
			||||||
  const usernameFallback =
 | 
					 | 
				
			||||||
    user.username ?? (user.firstName ?? "") + (user.lastName ?? "");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // For the display name, if it for some reason is empty, fallback to username
 | 
					 | 
				
			||||||
  let nameFallback = (user.firstName ?? "") + (user.lastName ?? "");
 | 
					 | 
				
			||||||
  if (nameFallback === "") {
 | 
					 | 
				
			||||||
    nameFallback = usernameFallback;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const result = await db.insert(usersTable).values({
 | 
					 | 
				
			||||||
    id: userId,
 | 
					 | 
				
			||||||
    // this is used for path, make sure this is unique
 | 
					 | 
				
			||||||
    username: usernameFallback,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // this is for display name, maybe different from username
 | 
					 | 
				
			||||||
    name: nameFallback,
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
import { CodeBlock } from "@/components/CodeBlock";
 | 
					import { CodeBlock } from "@/components/CodeBlock";
 | 
				
			||||||
 | 
					import { Button } from "@/components/ui/button";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  Dialog,
 | 
					  Dialog,
 | 
				
			||||||
  DialogContent,
 | 
					  DialogContent,
 | 
				
			||||||
@ -13,7 +14,9 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
 | 
				
			|||||||
import { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow";
 | 
					import { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow";
 | 
				
			||||||
import { getRelativeTime } from "@/lib/getRelativeTime";
 | 
					import { getRelativeTime } from "@/lib/getRelativeTime";
 | 
				
			||||||
import type { findAllDeployments } from "@/server/findAllRuns";
 | 
					import type { findAllDeployments } from "@/server/findAllRuns";
 | 
				
			||||||
 | 
					import { ExternalLink } from "lucide-react";
 | 
				
			||||||
import { headers } from "next/headers";
 | 
					import { headers } from "next/headers";
 | 
				
			||||||
 | 
					import Link from "next/link";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const curlTemplate = `
 | 
					const curlTemplate = `
 | 
				
			||||||
curl --request POST \
 | 
					curl --request POST \
 | 
				
			||||||
@ -72,7 +75,9 @@ export function DeploymentDisplay({
 | 
				
			|||||||
    <Dialog>
 | 
					    <Dialog>
 | 
				
			||||||
      <DialogTrigger asChild className="appearance-none hover:cursor-pointer">
 | 
					      <DialogTrigger asChild className="appearance-none hover:cursor-pointer">
 | 
				
			||||||
        <TableRow>
 | 
					        <TableRow>
 | 
				
			||||||
          <TableCell className="capitalize">{deployment.environment}</TableCell>
 | 
					          <TableCell className="capitalize truncate">
 | 
				
			||||||
 | 
					            {deployment.environment}
 | 
				
			||||||
 | 
					          </TableCell>
 | 
				
			||||||
          <TableCell className="font-medium truncate">
 | 
					          <TableCell className="font-medium truncate">
 | 
				
			||||||
            {deployment.version?.version}
 | 
					            {deployment.version?.version}
 | 
				
			||||||
          </TableCell>
 | 
					          </TableCell>
 | 
				
			||||||
@ -92,34 +97,53 @@ export function DeploymentDisplay({
 | 
				
			|||||||
          <DialogDescription>Code for your deployment client</DialogDescription>
 | 
					          <DialogDescription>Code for your deployment client</DialogDescription>
 | 
				
			||||||
        </DialogHeader>
 | 
					        </DialogHeader>
 | 
				
			||||||
        <ScrollArea className="max-h-[600px]">
 | 
					        <ScrollArea className="max-h-[600px]">
 | 
				
			||||||
          <Tabs defaultValue="js" className="w-full">
 | 
					          {deployment.environment !== "public-share" ? (
 | 
				
			||||||
            <TabsList className="grid w-fit grid-cols-2">
 | 
					            <Tabs defaultValue="js" className="w-full">
 | 
				
			||||||
              <TabsTrigger value="js">js</TabsTrigger>
 | 
					              <TabsList className="grid w-fit grid-cols-2">
 | 
				
			||||||
              <TabsTrigger value="curl">curl</TabsTrigger>
 | 
					                <TabsTrigger value="js">js</TabsTrigger>
 | 
				
			||||||
            </TabsList>
 | 
					                <TabsTrigger value="curl">curl</TabsTrigger>
 | 
				
			||||||
            <TabsContent className="flex flex-col gap-2" value="js">
 | 
					              </TabsList>
 | 
				
			||||||
              Trigger the workflow
 | 
					              <TabsContent className="flex flex-col gap-2" value="js">
 | 
				
			||||||
              <CodeBlock
 | 
					                Trigger the workflow
 | 
				
			||||||
                lang="js"
 | 
					                <CodeBlock
 | 
				
			||||||
                code={formatCode(jsTemplate, deployment, domain, workflowInput)}
 | 
					                  lang="js"
 | 
				
			||||||
              />
 | 
					                  code={formatCode(
 | 
				
			||||||
              Check the status of the run, and retrieve the outputs
 | 
					                    jsTemplate,
 | 
				
			||||||
              <CodeBlock
 | 
					                    deployment,
 | 
				
			||||||
                lang="js"
 | 
					                    domain,
 | 
				
			||||||
                code={formatCode(jsTemplate_checkStatus, deployment, domain)}
 | 
					                    workflowInput
 | 
				
			||||||
              />
 | 
					                  )}
 | 
				
			||||||
            </TabsContent>
 | 
					                />
 | 
				
			||||||
            <TabsContent className="flex flex-col gap-2" value="curl">
 | 
					                Check the status of the run, and retrieve the outputs
 | 
				
			||||||
              <CodeBlock
 | 
					                <CodeBlock
 | 
				
			||||||
                lang="bash"
 | 
					                  lang="js"
 | 
				
			||||||
                code={formatCode(curlTemplate, deployment, domain)}
 | 
					                  code={formatCode(jsTemplate_checkStatus, deployment, domain)}
 | 
				
			||||||
              />
 | 
					                />
 | 
				
			||||||
              <CodeBlock
 | 
					              </TabsContent>
 | 
				
			||||||
                lang="bash"
 | 
					              <TabsContent className="flex flex-col gap-2" value="curl">
 | 
				
			||||||
                code={formatCode(curlTemplate_checkStatus, deployment, domain)}
 | 
					                <CodeBlock
 | 
				
			||||||
              />
 | 
					                  lang="bash"
 | 
				
			||||||
            </TabsContent>
 | 
					                  code={formatCode(curlTemplate, deployment, domain)}
 | 
				
			||||||
          </Tabs>
 | 
					                />
 | 
				
			||||||
 | 
					                <CodeBlock
 | 
				
			||||||
 | 
					                  lang="bash"
 | 
				
			||||||
 | 
					                  code={formatCode(
 | 
				
			||||||
 | 
					                    curlTemplate_checkStatus,
 | 
				
			||||||
 | 
					                    deployment,
 | 
				
			||||||
 | 
					                    domain
 | 
				
			||||||
 | 
					                  )}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              </TabsContent>
 | 
				
			||||||
 | 
					            </Tabs>
 | 
				
			||||||
 | 
					          ) : (
 | 
				
			||||||
 | 
					            <div className="w-full text-right">
 | 
				
			||||||
 | 
					              <Button asChild className="gap-2">
 | 
				
			||||||
 | 
					                <Link href={`/share/${deployment.id}`} target="_blank">
 | 
				
			||||||
 | 
					                  View Share Page <ExternalLink size={14} />
 | 
				
			||||||
 | 
					                </Link>
 | 
				
			||||||
 | 
					              </Button>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
        </ScrollArea>
 | 
					        </ScrollArea>
 | 
				
			||||||
      </DialogContent>
 | 
					      </DialogContent>
 | 
				
			||||||
    </Dialog>
 | 
					    </Dialog>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,26 +1,22 @@
 | 
				
			|||||||
"use client";
 | 
					"use client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Badge } from "./ui/badge";
 | 
					 | 
				
			||||||
import macBookMainImage from "@/assets/images/macbook-main.png";
 | 
					 | 
				
			||||||
import { Section } from "@/components/Section";
 | 
					import { Section } from "@/components/Section";
 | 
				
			||||||
import { cn } from "@/lib/utils";
 | 
					import { cn } from "@/lib/utils";
 | 
				
			||||||
import Image from "next/image";
 | 
					import meta from "next-gen/config";
 | 
				
			||||||
import { Fragment } from "react";
 | 
					 | 
				
			||||||
import meta from 'next-gen/config';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
function isDevelopment() {
 | 
					function isDevelopment() {
 | 
				
			||||||
  return process.env.NODE_ENV === "development";
 | 
					  return process.env.NODE_ENV === "development";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function FeatureCard(props: {
 | 
					function FeatureCard(props: {
 | 
				
			||||||
  className?: String;
 | 
					  className?: string;
 | 
				
			||||||
  title: React.ReactNode;
 | 
					  title: React.ReactNode;
 | 
				
			||||||
  description: String;
 | 
					  description: string;
 | 
				
			||||||
}) {
 | 
					}) {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div
 | 
					    <div
 | 
				
			||||||
      className={cn(
 | 
					      className={cn(
 | 
				
			||||||
        "group relative text-center bg-opacity-20 rounded-lg py-6 ring-1 shadow-sm ring-stone-200/50 overflow-hidden",
 | 
					        "group relative text-center bg-opacity-20 rounded-lg py-6 ring-1 shadow-sm ring-stone-200/50 overflow-hidden"
 | 
				
			||||||
        // props.className,
 | 
					        // props.className,
 | 
				
			||||||
      )}
 | 
					      )}
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
@ -28,14 +24,14 @@ function FeatureCard(props: {
 | 
				
			|||||||
      <div
 | 
					      <div
 | 
				
			||||||
        className={cn(
 | 
					        className={cn(
 | 
				
			||||||
          "opacity-60 group-hover:opacity-100 transition-all -z-[5] absolute top-0 h-full w-full duration-700",
 | 
					          "opacity-60 group-hover:opacity-100 transition-all -z-[5] absolute top-0 h-full w-full duration-700",
 | 
				
			||||||
          props.className,
 | 
					          props.className
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
      ></div>
 | 
					      />
 | 
				
			||||||
      <div className="opacity-60 group-hover:opacity-100 absolute top-0 inset-0 -z-[5] h-full w-full bg-[radial-gradient(#e5e7eb_1px,transparent_1px)] [background-size:16px_16px] [mask-image:radial-gradient(ellipse_50%_50%_at_50%_50%,#000_70%,transparent_100%)]"></div>
 | 
					      <div className="opacity-60 group-hover:opacity-100 absolute top-0 inset-0 -z-[5] h-full w-full bg-[radial-gradient(#e5e7eb_1px,transparent_1px)] [background-size:16px_16px] [mask-image:radial-gradient(ellipse_50%_50%_at_50%_50%,#000_70%,transparent_100%)]" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <div className="">
 | 
					      <div className="">
 | 
				
			||||||
        <div className="font-mono text-lg ">{props.title}</div>
 | 
					        <div className="font-mono text-lg ">{props.title}</div>
 | 
				
			||||||
        <div className="divider px-4 py-0 h-[1px] opacity-30 my-2"></div>
 | 
					        <div className="divider px-4 py-0 h-[1px] opacity-30 my-2" />
 | 
				
			||||||
        <div className="px-8 text-stone-800 ">{props.description}</div>
 | 
					        <div className="px-8 text-stone-800 ">{props.description}</div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
@ -86,7 +82,6 @@ export default function Main() {
 | 
				
			|||||||
            ></Image> */}
 | 
					            ></Image> */}
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </Section>
 | 
					        </Section>
 | 
				
			||||||
 | 
					 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <footer className="text-base-content mx-auto flex flex-col md:flex-row items-center justify-center w-full max-w-5xl  gap-4 p-10 ">
 | 
					      <footer className="text-base-content mx-auto flex flex-col md:flex-row items-center justify-center w-full max-w-5xl  gap-4 p-10 ">
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@ import { useEffect, useState } from "react";
 | 
				
			|||||||
import { useMediaQuery } from "usehooks-ts";
 | 
					import { useMediaQuery } from "usehooks-ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function Navbar() {
 | 
					export function Navbar() {
 | 
				
			||||||
  const _isDesktop = useMediaQuery("(min-width: 768px)");
 | 
					  const _isDesktop = useMediaQuery("(min-width: 1024px)");
 | 
				
			||||||
  const [isDesktop, setIsDesktop] = useState(true);
 | 
					  const [isDesktop, setIsDesktop] = useState(true);
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    setIsDesktop(_isDesktop);
 | 
					    setIsDesktop(_isDesktop);
 | 
				
			||||||
 | 
				
			|||||||
@ -34,13 +34,19 @@ export function NavbarMenu({ className }: { className?: string }) {
 | 
				
			|||||||
      <Tabs
 | 
					      <Tabs
 | 
				
			||||||
        defaultValue={pathname}
 | 
					        defaultValue={pathname}
 | 
				
			||||||
        className="w-[300px] hidden lg:flex pointer-events-auto"
 | 
					        className="w-[300px] hidden lg:flex pointer-events-auto"
 | 
				
			||||||
        onValueChange={(value) => {
 | 
					        // onValueChange={(value) => {
 | 
				
			||||||
          router.push(value);
 | 
					
 | 
				
			||||||
        }}
 | 
					        // }}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <TabsList className="grid w-full grid-cols-3">
 | 
					        <TabsList className="grid w-full grid-cols-3">
 | 
				
			||||||
          {pages.map((page) => (
 | 
					          {pages.map((page) => (
 | 
				
			||||||
            <TabsTrigger key={page.name} value={page.path}>
 | 
					            <TabsTrigger
 | 
				
			||||||
 | 
					              key={page.name}
 | 
				
			||||||
 | 
					              value={page.path}
 | 
				
			||||||
 | 
					              onClick={() => {
 | 
				
			||||||
 | 
					                router.push(page.path);
 | 
				
			||||||
 | 
					              }}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
              {page.name}
 | 
					              {page.name}
 | 
				
			||||||
            </TabsTrigger>
 | 
					            </TabsTrigger>
 | 
				
			||||||
          ))}
 | 
					          ))}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,9 @@
 | 
				
			|||||||
"use client";
 | 
					"use client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  plainInputsToZod,
 | 
				
			||||||
 | 
					  workflowVersionInputsToZod,
 | 
				
			||||||
 | 
					} from "../lib/workflowVersionInputsToZod";
 | 
				
			||||||
import { callServerPromise } from "./callServerPromise";
 | 
					import { callServerPromise } from "./callServerPromise";
 | 
				
			||||||
import fetcher from "./fetcher";
 | 
					import fetcher from "./fetcher";
 | 
				
			||||||
import { LoadingIcon } from "@/components/LoadingIcon";
 | 
					import { LoadingIcon } from "@/components/LoadingIcon";
 | 
				
			||||||
@ -29,6 +33,7 @@ import {
 | 
				
			|||||||
  SelectTrigger,
 | 
					  SelectTrigger,
 | 
				
			||||||
  SelectValue,
 | 
					  SelectValue,
 | 
				
			||||||
} from "@/components/ui/select";
 | 
					} from "@/components/ui/select";
 | 
				
			||||||
 | 
					import { Skeleton } from "@/components/ui/skeleton";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  Table,
 | 
					  Table,
 | 
				
			||||||
  TableBody,
 | 
					  TableBody,
 | 
				
			||||||
@ -38,17 +43,26 @@ import {
 | 
				
			|||||||
  TableRow,
 | 
					  TableRow,
 | 
				
			||||||
} from "@/components/ui/table";
 | 
					} from "@/components/ui/table";
 | 
				
			||||||
import type { workflowAPINodeType } from "@/db/schema";
 | 
					import type { workflowAPINodeType } from "@/db/schema";
 | 
				
			||||||
import { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow";
 | 
					import type { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow";
 | 
				
			||||||
import { createRun } from "@/server/createRun";
 | 
					import { checkStatus, createRun } from "@/server/createRun";
 | 
				
			||||||
import { createDeployments } from "@/server/curdDeploments";
 | 
					import { createDeployments } from "@/server/curdDeploments";
 | 
				
			||||||
import type { getMachines } from "@/server/curdMachine";
 | 
					import type { getMachines } from "@/server/curdMachine";
 | 
				
			||||||
import type { findFirstTableWithVersion } from "@/server/findFirstTableWithVersion";
 | 
					import type { findFirstTableWithVersion } from "@/server/findFirstTableWithVersion";
 | 
				
			||||||
import { Copy, ExternalLink, Info, MoreVertical, Play } from "lucide-react";
 | 
					import { useAuth, useClerk } from "@clerk/nextjs";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Copy,
 | 
				
			||||||
 | 
					  ExternalLink,
 | 
				
			||||||
 | 
					  Info,
 | 
				
			||||||
 | 
					  MoreVertical,
 | 
				
			||||||
 | 
					  Play,
 | 
				
			||||||
 | 
					  Share,
 | 
				
			||||||
 | 
					} from "lucide-react";
 | 
				
			||||||
import { parseAsInteger, useQueryState } from "next-usequerystate";
 | 
					import { parseAsInteger, useQueryState } from "next-usequerystate";
 | 
				
			||||||
import { useMemo, useState } from "react";
 | 
					import { useEffect, useMemo, useState } from "react";
 | 
				
			||||||
import { toast } from "sonner";
 | 
					import { toast } from "sonner";
 | 
				
			||||||
import useSWR from "swr";
 | 
					import useSWR from "swr";
 | 
				
			||||||
import { z } from "zod";
 | 
					import type { z } from "zod";
 | 
				
			||||||
 | 
					import { create } from "zustand";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function VersionSelect({
 | 
					export function VersionSelect({
 | 
				
			||||||
  workflow,
 | 
					  workflow,
 | 
				
			||||||
@ -121,6 +135,168 @@ function useSelectedMachine(machines: Awaited<ReturnType<typeof getMachines>>) {
 | 
				
			|||||||
  return a;
 | 
					  return a;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type PublicRunStore = {
 | 
				
			||||||
 | 
					  image: string;
 | 
				
			||||||
 | 
					  loading: boolean;
 | 
				
			||||||
 | 
					  runId: string;
 | 
				
			||||||
 | 
					  status: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  setImage: (image: string) => void;
 | 
				
			||||||
 | 
					  setLoading: (loading: boolean) => void;
 | 
				
			||||||
 | 
					  setRunId: (runId: string) => void;
 | 
				
			||||||
 | 
					  setStatus: (status: string) => void;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const publicRunStore = create<PublicRunStore>((set) => ({
 | 
				
			||||||
 | 
					  image: "",
 | 
				
			||||||
 | 
					  loading: false,
 | 
				
			||||||
 | 
					  runId: "",
 | 
				
			||||||
 | 
					  status: "",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  setImage: (image) => set({ image }),
 | 
				
			||||||
 | 
					  setLoading: (loading) => set({ loading }),
 | 
				
			||||||
 | 
					  setRunId: (runId) => set({ runId }),
 | 
				
			||||||
 | 
					  setStatus: (status) => set({ status }),
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function PublicRunOutputs() {
 | 
				
			||||||
 | 
					  const { image, loading, runId, status, setStatus, setImage, setLoading } =
 | 
				
			||||||
 | 
					    publicRunStore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (!runId) return;
 | 
				
			||||||
 | 
					    const interval = setInterval(() => {
 | 
				
			||||||
 | 
					      checkStatus(runId).then((res) => {
 | 
				
			||||||
 | 
					        console.log(res?.status);
 | 
				
			||||||
 | 
					        if (res) setStatus(res.status);
 | 
				
			||||||
 | 
					        if (res && res.status === "success") {
 | 
				
			||||||
 | 
					          setImage(res.outputs[0]?.data.images[0].url);
 | 
				
			||||||
 | 
					          setLoading(false);
 | 
				
			||||||
 | 
					          clearInterval(interval);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }, 2000);
 | 
				
			||||||
 | 
					    return () => clearInterval(interval);
 | 
				
			||||||
 | 
					  }, [runId]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="border border-gray-200 w-full square h-[400px] rounded-lg relative">
 | 
				
			||||||
 | 
					      {!loading && image && (
 | 
				
			||||||
 | 
					        <img
 | 
				
			||||||
 | 
					          className="w-full h-full object-contain"
 | 
				
			||||||
 | 
					          src={image}
 | 
				
			||||||
 | 
					          alt="Generated image"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					      {loading && (
 | 
				
			||||||
 | 
					        <div className="absolute top-0 left-0 w-full h-full flex items-center justify-center gap-2">
 | 
				
			||||||
 | 
					          {status} <LoadingIcon />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					      {loading && <Skeleton className="w-full h-full" />}
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function RunWorkflowInline({
 | 
				
			||||||
 | 
					  inputs,
 | 
				
			||||||
 | 
					  workflow_version_id,
 | 
				
			||||||
 | 
					  machine_id,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  inputs: ReturnType<typeof getInputsFromWorkflow>;
 | 
				
			||||||
 | 
					  workflow_version_id: string;
 | 
				
			||||||
 | 
					  machine_id: string;
 | 
				
			||||||
 | 
					}) {
 | 
				
			||||||
 | 
					  const [values, setValues] = useState<Record<string, string>>({});
 | 
				
			||||||
 | 
					  const [isLoading, setIsLoading] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const user = useAuth();
 | 
				
			||||||
 | 
					  const clerk = useClerk();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const schema = useMemo(() => {
 | 
				
			||||||
 | 
					    return plainInputsToZod(inputs);
 | 
				
			||||||
 | 
					  }, [inputs]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const {
 | 
				
			||||||
 | 
					    setRunId,
 | 
				
			||||||
 | 
					    loading,
 | 
				
			||||||
 | 
					    setLoading: setLoading2,
 | 
				
			||||||
 | 
					    setStatus,
 | 
				
			||||||
 | 
					  } = publicRunStore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const runWorkflow = async () => {
 | 
				
			||||||
 | 
					    console.log();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!user.isSignedIn) {
 | 
				
			||||||
 | 
					      clerk.openSignIn({
 | 
				
			||||||
 | 
					        redirectUrl: window.location.href,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      console.log("hi");
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    console.log(values);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const val = Object.keys(values).length > 0 ? values : undefined;
 | 
				
			||||||
 | 
					    setLoading2(true);
 | 
				
			||||||
 | 
					    setIsLoading(true);
 | 
				
			||||||
 | 
					    setStatus("preparing");
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const origin = window.location.origin;
 | 
				
			||||||
 | 
					      const a = await callServerPromise(
 | 
				
			||||||
 | 
					        createRun({
 | 
				
			||||||
 | 
					          origin,
 | 
				
			||||||
 | 
					          workflow_version_id: workflow_version_id,
 | 
				
			||||||
 | 
					          machine_id: machine_id,
 | 
				
			||||||
 | 
					          inputs: val,
 | 
				
			||||||
 | 
					          isManualRun: true,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      if (a && !("error" in a)) {
 | 
				
			||||||
 | 
					        setRunId(a.workflow_run_id);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        setLoading2(false);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      console.log(a);
 | 
				
			||||||
 | 
					      setIsLoading(false);
 | 
				
			||||||
 | 
					    } catch (error) {
 | 
				
			||||||
 | 
					      setIsLoading(false);
 | 
				
			||||||
 | 
					      setLoading2(false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <>
 | 
				
			||||||
 | 
					      {schema && (
 | 
				
			||||||
 | 
					        <AutoForm
 | 
				
			||||||
 | 
					          formSchema={schema}
 | 
				
			||||||
 | 
					          values={values}
 | 
				
			||||||
 | 
					          onValuesChange={setValues}
 | 
				
			||||||
 | 
					          onSubmit={runWorkflow}
 | 
				
			||||||
 | 
					          className="px-1"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <div className="flex justify-end">
 | 
				
			||||||
 | 
					            <AutoFormSubmit disabled={isLoading || loading}>
 | 
				
			||||||
 | 
					              Run
 | 
				
			||||||
 | 
					              <span className="ml-2">
 | 
				
			||||||
 | 
					                {isLoading || loading ? <LoadingIcon /> : <Play size={14} />}
 | 
				
			||||||
 | 
					              </span>
 | 
				
			||||||
 | 
					            </AutoFormSubmit>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </AutoForm>
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					      {!schema && (
 | 
				
			||||||
 | 
					        <Button
 | 
				
			||||||
 | 
					          className="gap-2"
 | 
				
			||||||
 | 
					          disabled={isLoading || loading}
 | 
				
			||||||
 | 
					          onClick={runWorkflow}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          Confirm {isLoading || loading ? <LoadingIcon /> : <Play size={14} />}
 | 
				
			||||||
 | 
					        </Button>
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					    </>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function RunWorkflowButton({
 | 
					export function RunWorkflowButton({
 | 
				
			||||||
  workflow,
 | 
					  workflow,
 | 
				
			||||||
  machines,
 | 
					  machines,
 | 
				
			||||||
@ -143,17 +319,10 @@ export function RunWorkflowButton({
 | 
				
			|||||||
      workflow,
 | 
					      workflow,
 | 
				
			||||||
      version
 | 
					      version
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    const inputs = getInputsFromWorkflow(workflow_version);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!inputs) return null;
 | 
					    if (!workflow_version) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return z.object({
 | 
					    return workflowVersionInputsToZod(workflow_version);
 | 
				
			||||||
      ...Object.fromEntries(
 | 
					 | 
				
			||||||
        inputs?.map((x) => {
 | 
					 | 
				
			||||||
          return [x?.input_id, z.string().optional()];
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  }, [version]);
 | 
					  }, [version]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const runWorkflow = async () => {
 | 
					  const runWorkflow = async () => {
 | 
				
			||||||
@ -228,8 +397,6 @@ export function RunWorkflowButton({
 | 
				
			|||||||
            Confirm {isLoading ? <LoadingIcon /> : <Play size={14} />}
 | 
					            Confirm {isLoading ? <LoadingIcon /> : <Play size={14} />}
 | 
				
			||||||
          </Button>
 | 
					          </Button>
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
        {/* </div> */}
 | 
					 | 
				
			||||||
        {/* <div className="max-h-96 overflow-y-scroll">{view}</div> */}
 | 
					 | 
				
			||||||
      </DialogContent>
 | 
					      </DialogContent>
 | 
				
			||||||
    </Dialog>
 | 
					    </Dialog>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
@ -301,6 +468,55 @@ export function CreateDeploymentButton({
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function CreateShareButton({
 | 
				
			||||||
 | 
					  workflow,
 | 
				
			||||||
 | 
					  machines,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  workflow: Awaited<ReturnType<typeof findFirstTableWithVersion>>;
 | 
				
			||||||
 | 
					  machines: Awaited<ReturnType<typeof getMachines>>;
 | 
				
			||||||
 | 
					}) {
 | 
				
			||||||
 | 
					  const [version] = useQueryState("version", {
 | 
				
			||||||
 | 
					    defaultValue: workflow?.versions[0].version ?? 1,
 | 
				
			||||||
 | 
					    ...parseAsInteger,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  const [machine] = useSelectedMachine(machines);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [isLoading, setIsLoading] = useState(false);
 | 
				
			||||||
 | 
					  const workflow_version_id = workflow?.versions.find(
 | 
				
			||||||
 | 
					    (x) => x.version === version
 | 
				
			||||||
 | 
					  )?.id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <DropdownMenu>
 | 
				
			||||||
 | 
					      <DropdownMenuTrigger asChild>
 | 
				
			||||||
 | 
					        <Button className="gap-2" disabled={isLoading} variant="outline">
 | 
				
			||||||
 | 
					          Share {isLoading ? <LoadingIcon /> : <Share size={14} />}
 | 
				
			||||||
 | 
					        </Button>
 | 
				
			||||||
 | 
					      </DropdownMenuTrigger>
 | 
				
			||||||
 | 
					      <DropdownMenuContent className="w-56">
 | 
				
			||||||
 | 
					        <DropdownMenuItem
 | 
				
			||||||
 | 
					          onClick={async () => {
 | 
				
			||||||
 | 
					            if (!workflow_version_id) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            setIsLoading(true);
 | 
				
			||||||
 | 
					            await callServerPromise(
 | 
				
			||||||
 | 
					              createDeployments(
 | 
				
			||||||
 | 
					                workflow.id,
 | 
				
			||||||
 | 
					                workflow_version_id,
 | 
				
			||||||
 | 
					                machine,
 | 
				
			||||||
 | 
					                "public-share"
 | 
				
			||||||
 | 
					              )
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            setIsLoading(false);
 | 
				
			||||||
 | 
					          }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          Public
 | 
				
			||||||
 | 
					        </DropdownMenuItem>
 | 
				
			||||||
 | 
					      </DropdownMenuContent>
 | 
				
			||||||
 | 
					    </DropdownMenu>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function CopyWorkflowVersion({
 | 
					export function CopyWorkflowVersion({
 | 
				
			||||||
  workflow,
 | 
					  workflow,
 | 
				
			||||||
}: {
 | 
					}: {
 | 
				
			||||||
 | 
				
			|||||||
@ -13,8 +13,18 @@ import type { DefaultValues } from "react-hook-form";
 | 
				
			|||||||
import { useForm } from "react-hook-form";
 | 
					import { useForm } from "react-hook-form";
 | 
				
			||||||
import type { z } from "zod";
 | 
					import type { z } from "zod";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function AutoFormSubmit({ children }: { children?: React.ReactNode }) {
 | 
					export function AutoFormSubmit({
 | 
				
			||||||
  return <Button type="submit">{children ?? "Submit"}</Button>;
 | 
					  children,
 | 
				
			||||||
 | 
					  disabled,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  children?: React.ReactNode;
 | 
				
			||||||
 | 
					  disabled?: boolean;
 | 
				
			||||||
 | 
					}) {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Button type="submit" disabled={disabled}>
 | 
				
			||||||
 | 
					      {children ?? "Submit"}
 | 
				
			||||||
 | 
					    </Button>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function AutoForm<SchemaType extends ZodObjectOrWrapped>({
 | 
					function AutoForm<SchemaType extends ZodObjectOrWrapped>({
 | 
				
			||||||
 | 
				
			|||||||
@ -97,6 +97,7 @@ export const workflowRunStatus = pgEnum("workflow_run_status", [
 | 
				
			|||||||
export const deploymentEnvironment = pgEnum("deployment_environment", [
 | 
					export const deploymentEnvironment = pgEnum("deployment_environment", [
 | 
				
			||||||
  "staging",
 | 
					  "staging",
 | 
				
			||||||
  "production",
 | 
					  "production",
 | 
				
			||||||
 | 
					  "public-share",
 | 
				
			||||||
]);
 | 
					]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const workflowRunOrigin = pgEnum("workflow_run_origin", [
 | 
					export const workflowRunOrigin = pgEnum("workflow_run_origin", [
 | 
				
			||||||
@ -265,6 +266,10 @@ export const deploymentsRelations = relations(deploymentsTable, ({ one }) => ({
 | 
				
			|||||||
    fields: [deploymentsTable.workflow_id],
 | 
					    fields: [deploymentsTable.workflow_id],
 | 
				
			||||||
    references: [workflowTable.id],
 | 
					    references: [workflowTable.id],
 | 
				
			||||||
  }),
 | 
					  }),
 | 
				
			||||||
 | 
					  user: one(usersTable, {
 | 
				
			||||||
 | 
					    fields: [deploymentsTable.user_id],
 | 
				
			||||||
 | 
					    references: [usersTable.id],
 | 
				
			||||||
 | 
					  }),
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const apiKeyTable = dbSchema.table("api_keys", {
 | 
					export const apiKeyTable = dbSchema.table("api_keys", {
 | 
				
			||||||
@ -286,3 +291,4 @@ export type UserType = InferSelectModel<typeof usersTable>;
 | 
				
			|||||||
export type WorkflowType = InferSelectModel<typeof workflowTable>;
 | 
					export type WorkflowType = InferSelectModel<typeof workflowTable>;
 | 
				
			||||||
export type MachineType = InferSelectModel<typeof machinesTable>;
 | 
					export type MachineType = InferSelectModel<typeof machinesTable>;
 | 
				
			||||||
export type WorkflowVersionType = InferSelectModel<typeof workflowVersionTable>;
 | 
					export type WorkflowVersionType = InferSelectModel<typeof workflowVersionTable>;
 | 
				
			||||||
 | 
					export type DeploymentType = InferSelectModel<typeof deploymentsTable>;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										25
									
								
								web/src/lib/setInitialUserData.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								web/src/lib/setInitialUserData.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					import { db } from "@/db/db";
 | 
				
			||||||
 | 
					import { usersTable } from "@/db/schema";
 | 
				
			||||||
 | 
					import { clerkClient } from "@clerk/nextjs";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function setInitialUserData(userId: string) {
 | 
				
			||||||
 | 
					  const user = await clerkClient.users.getUser(userId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // incase we dont have username such as google login, fallback to first name + last name
 | 
				
			||||||
 | 
					  const usernameFallback = user.username ?? (user.firstName ?? "") + (user.lastName ?? "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // For the display name, if it for some reason is empty, fallback to username
 | 
				
			||||||
 | 
					  let nameFallback = (user.firstName ?? "") + (user.lastName ?? "");
 | 
				
			||||||
 | 
					  if (nameFallback === "") {
 | 
				
			||||||
 | 
					    nameFallback = usernameFallback;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const result = await db.insert(usersTable).values({
 | 
				
			||||||
 | 
					    id: userId,
 | 
				
			||||||
 | 
					    // this is used for path, make sure this is unique
 | 
				
			||||||
 | 
					    username: usernameFallback,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // this is for display name, maybe different from username
 | 
				
			||||||
 | 
					    name: nameFallback,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										24
									
								
								web/src/lib/workflowVersionInputsToZod.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								web/src/lib/workflowVersionInputsToZod.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					import type { WorkflowVersionType } from "@/db/schema";
 | 
				
			||||||
 | 
					import { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow";
 | 
				
			||||||
 | 
					import { z } from "zod";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function workflowVersionInputsToZod(
 | 
				
			||||||
 | 
					  workflow_version: WorkflowVersionType
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					  const inputs = getInputsFromWorkflow(workflow_version);
 | 
				
			||||||
 | 
					  return plainInputsToZod(inputs);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function plainInputsToZod(
 | 
				
			||||||
 | 
					  inputs: ReturnType<typeof getInputsFromWorkflow>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					  if (!inputs) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return z.object({
 | 
				
			||||||
 | 
					    ...Object.fromEntries(
 | 
				
			||||||
 | 
					      inputs?.map((x) => {
 | 
				
			||||||
 | 
					        return [x?.input_id, z.string().optional()];
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -5,7 +5,7 @@ import { authMiddleware, redirectToSignIn } from "@clerk/nextjs";
 | 
				
			|||||||
// See https://clerk.com/docs/references/nextjs/auth-middleware for more information about configuring your Middleware
 | 
					// See https://clerk.com/docs/references/nextjs/auth-middleware for more information about configuring your Middleware
 | 
				
			||||||
export default authMiddleware({
 | 
					export default authMiddleware({
 | 
				
			||||||
  // debug: true,
 | 
					  // debug: true,
 | 
				
			||||||
  publicRoutes: ["/", "/api/(.*)", "/docs(.*)"],
 | 
					  publicRoutes: ["/", "/api/(.*)", "/docs(.*)", "/share(.*)"],
 | 
				
			||||||
  // publicRoutes: ["/", "/(.*)"],
 | 
					  // publicRoutes: ["/", "/(.*)"],
 | 
				
			||||||
  async afterAuth(auth, req, evt) {
 | 
					  async afterAuth(auth, req, evt) {
 | 
				
			||||||
    // redirect them to organization selection page
 | 
					    // redirect them to organization selection page
 | 
				
			||||||
 | 
				
			|||||||
@ -5,7 +5,9 @@ import { db } from "@/db/db";
 | 
				
			|||||||
import type { MachineType, WorkflowVersionType } from "@/db/schema";
 | 
					import type { MachineType, WorkflowVersionType } from "@/db/schema";
 | 
				
			||||||
import { machinesTable, workflowRunsTable } from "@/db/schema";
 | 
					import { machinesTable, workflowRunsTable } from "@/db/schema";
 | 
				
			||||||
import type { APIKeyUserType } from "@/server/APIKeyBodyRequest";
 | 
					import type { APIKeyUserType } from "@/server/APIKeyBodyRequest";
 | 
				
			||||||
 | 
					import { getRunsData } from "@/server/getRunsData";
 | 
				
			||||||
import { ComfyAPI_Run } from "@/types/ComfyAPI_Run";
 | 
					import { ComfyAPI_Run } from "@/types/ComfyAPI_Run";
 | 
				
			||||||
 | 
					import { auth } from "@clerk/nextjs";
 | 
				
			||||||
import { and, eq } from "drizzle-orm";
 | 
					import { and, eq } from "drizzle-orm";
 | 
				
			||||||
import { revalidatePath } from "next/cache";
 | 
					import { revalidatePath } from "next/cache";
 | 
				
			||||||
import "server-only";
 | 
					import "server-only";
 | 
				
			||||||
@ -219,3 +221,10 @@ export const createRun = withServerPromise(
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function checkStatus(run_id: string) {
 | 
				
			||||||
 | 
					  const { userId } = auth();
 | 
				
			||||||
 | 
					  if (!userId) throw new Error("User not found");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return await getRunsData(run_id);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
"use server";
 | 
					"use server";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { db } from "@/db/db";
 | 
					import { db } from "@/db/db";
 | 
				
			||||||
 | 
					import type { DeploymentType } from "@/db/schema";
 | 
				
			||||||
import { deploymentsTable, workflowTable } from "@/db/schema";
 | 
					import { deploymentsTable, workflowTable } from "@/db/schema";
 | 
				
			||||||
import { auth } from "@clerk/nextjs";
 | 
					import { auth } from "@clerk/nextjs";
 | 
				
			||||||
import { and, eq, isNull } from "drizzle-orm";
 | 
					import { and, eq, isNull } from "drizzle-orm";
 | 
				
			||||||
@ -11,7 +12,7 @@ export async function createDeployments(
 | 
				
			|||||||
  workflow_id: string,
 | 
					  workflow_id: string,
 | 
				
			||||||
  version_id: string,
 | 
					  version_id: string,
 | 
				
			||||||
  machine_id: string,
 | 
					  machine_id: string,
 | 
				
			||||||
  environment: "production" | "staging"
 | 
					  environment: DeploymentType["environment"]
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
  const { userId } = auth();
 | 
					  const { userId } = auth();
 | 
				
			||||||
  if (!userId) throw new Error("No user id");
 | 
					  if (!userId) throw new Error("No user id");
 | 
				
			||||||
@ -80,3 +81,26 @@ export async function findAllDeployments() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  return deployments;
 | 
					  return deployments;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function findSharedDeployment(workflow_id: string) {
 | 
				
			||||||
 | 
					  const deploymentData = await db.query.deploymentsTable.findFirst({
 | 
				
			||||||
 | 
					    where: and(
 | 
				
			||||||
 | 
					      eq(deploymentsTable.environment, "public-share"),
 | 
				
			||||||
 | 
					      eq(deploymentsTable.id, workflow_id)
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    with: {
 | 
				
			||||||
 | 
					      user: true,
 | 
				
			||||||
 | 
					      machine: true,
 | 
				
			||||||
 | 
					      workflow: {
 | 
				
			||||||
 | 
					        columns: {
 | 
				
			||||||
 | 
					          name: true,
 | 
				
			||||||
 | 
					          org_id: true,
 | 
				
			||||||
 | 
					          user_id: true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      version: true,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return deploymentData;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										72
									
								
								web/src/server/getRunsData.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								web/src/server/getRunsData.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,72 @@
 | 
				
			|||||||
 | 
					import { db } from "@/db/db";
 | 
				
			||||||
 | 
					import { workflowRunsTable } from "@/db/schema";
 | 
				
			||||||
 | 
					import type { APIKeyUserType } from "@/server/APIKeyBodyRequest";
 | 
				
			||||||
 | 
					import { replaceCDNUrl } from "@/server/replaceCDNUrl";
 | 
				
			||||||
 | 
					import { and, eq } from "drizzle-orm";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function getRunsData(run_id: string, user?: APIKeyUserType) {
 | 
				
			||||||
 | 
					  const data = await db.query.workflowRunsTable.findFirst({
 | 
				
			||||||
 | 
					    where: and(eq(workflowRunsTable.id, run_id)),
 | 
				
			||||||
 | 
					    with: {
 | 
				
			||||||
 | 
					      workflow: {
 | 
				
			||||||
 | 
					        columns: {
 | 
				
			||||||
 | 
					          org_id: true,
 | 
				
			||||||
 | 
					          user_id: true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      outputs: {
 | 
				
			||||||
 | 
					        columns: {
 | 
				
			||||||
 | 
					          data: true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!data) {
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (user) {
 | 
				
			||||||
 | 
					    if (user.org_id) {
 | 
				
			||||||
 | 
					      // is org api call, check org only
 | 
				
			||||||
 | 
					      if (data.workflow.org_id != user.org_id) {
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      // is user api call, check user only
 | 
				
			||||||
 | 
					      if (
 | 
				
			||||||
 | 
					        data.workflow.user_id != user.user_id &&
 | 
				
			||||||
 | 
					        data.workflow.org_id == null
 | 
				
			||||||
 | 
					      ) {
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (data) {
 | 
				
			||||||
 | 
					    // Fill in the CDN url
 | 
				
			||||||
 | 
					    if (data?.status === "success" && data?.outputs?.length > 0) {
 | 
				
			||||||
 | 
					      for (let i = 0; i < data.outputs.length; i++) {
 | 
				
			||||||
 | 
					        const output = data.outputs[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (output.data?.images !== undefined) {
 | 
				
			||||||
 | 
					          for (let j = 0; j < output.data?.images.length; j++) {
 | 
				
			||||||
 | 
					            const element = output.data?.images[j];
 | 
				
			||||||
 | 
					            element.url = replaceCDNUrl(
 | 
				
			||||||
 | 
					              `${process.env.SPACES_ENDPOINT}/${process.env.SPACES_BUCKET}/outputs/runs/${data.id}/${element.filename}`
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        } else if (output.data?.files !== undefined) {
 | 
				
			||||||
 | 
					          for (let j = 0; j < output.data?.files.length; j++) {
 | 
				
			||||||
 | 
					            const element = output.data?.files[j];
 | 
				
			||||||
 | 
					            element.url = replaceCDNUrl(
 | 
				
			||||||
 | 
					              `${process.env.SPACES_ENDPOINT}/${process.env.SPACES_BUCKET}/outputs/runs/${data.id}/${element.filename}`
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return data;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -2,9 +2,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { RunOutputs } from "@/components/RunOutputs";
 | 
					import { RunOutputs } from "@/components/RunOutputs";
 | 
				
			||||||
import { db } from "@/db/db";
 | 
					import { db } from "@/db/db";
 | 
				
			||||||
import { workflowRunOutputs, workflowRunsTable } from "@/db/schema";
 | 
					import { workflowRunOutputs } from "@/db/schema";
 | 
				
			||||||
import type { APIKeyUserType } from "@/server/APIKeyBodyRequest";
 | 
					import { eq } from "drizzle-orm";
 | 
				
			||||||
import { and, eq } from "drizzle-orm";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export async function getRunsOutputDisplay(run_id: string) {
 | 
					export async function getRunsOutputDisplay(run_id: string) {
 | 
				
			||||||
  return <RunOutputs run_id={run_id} />;
 | 
					  return <RunOutputs run_id={run_id} />;
 | 
				
			||||||
@ -17,40 +16,3 @@ export async function getRunsOutput(run_id: string) {
 | 
				
			|||||||
    .from(workflowRunOutputs)
 | 
					    .from(workflowRunOutputs)
 | 
				
			||||||
    .where(eq(workflowRunOutputs.run_id, run_id));
 | 
					    .where(eq(workflowRunOutputs.run_id, run_id));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
export async function getRunsData(user: APIKeyUserType, run_id: string) {
 | 
					 | 
				
			||||||
  const data = await db.query.workflowRunsTable.findFirst({
 | 
					 | 
				
			||||||
    where: and(eq(workflowRunsTable.id, run_id)),
 | 
					 | 
				
			||||||
    with: {
 | 
					 | 
				
			||||||
      workflow: {
 | 
					 | 
				
			||||||
        columns: {
 | 
					 | 
				
			||||||
          org_id: true,
 | 
					 | 
				
			||||||
          user_id: true,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      outputs: {
 | 
					 | 
				
			||||||
        columns: {
 | 
					 | 
				
			||||||
          data: true,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!data) {
 | 
					 | 
				
			||||||
    return null;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (user.org_id) {
 | 
					 | 
				
			||||||
    // is org api call, check org only
 | 
					 | 
				
			||||||
    if (data.workflow.org_id != user.org_id) {
 | 
					 | 
				
			||||||
      return null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    // is user api call, check user only
 | 
					 | 
				
			||||||
    if (data.workflow.user_id != user.user_id && data.workflow.org_id == null) {
 | 
					 | 
				
			||||||
      return null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return data;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user