Compare commits

..
Author SHA1 Message Date
Nicholas Koben Kao ed659ebdb8 schema 2024-01-22 19:05:24 -08:00
Nicholas Koben Kao f6a1b88dda rest 2024-01-22 19:05:18 -08:00
Nicholas Koben Kao fed7b380b6 work 2024-01-22 17:23:35 -08:00
Nicholas Koben Kao 90cec6b778 schema 2024-01-20 22:01:11 -08:00
Nicholas Koben Kao 7b61fea849 volume work 2024-01-20 19:54:35 -08:00
Nicholas Koben Kao 60471a8e01 model in voluems 2024-01-20 12:53:48 -08:00
144 changed files with 1951 additions and 17865 deletions
-23
View File
@@ -1,23 +0,0 @@
ARG VARIANT=18-bullseye
FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:${VARIANT}
# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>
WORKDIR "/"
# Install fly
RUN curl -L https://fly.io/install.sh | sh
ENV FLYCTL_INSTALL="/root/.fly"
ENV PATH="$FLYCTL_INSTALL/bin:$PATH"
RUN sudo apt-get update
RUN sudo apt-get install python3-pip python3 -y
RUN pip3 install modal
# RUN echo 'export FLYCTL_INSTALL="/home/node/.fly"' >> ~/.bashrc
# RUN echo 'export PATH="$FLYCTL_INSTALL/bin:$PATH"' >> ~/.bashrc
RUN npm install -g bun
-22
View File
@@ -1,22 +0,0 @@
{
"name": "Comfy Deploy Dev",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
"postCreateCommand": "cd web && bun install && bun run migrate-local",
"remoteUser": "root",
"customizations": {
"vscode": {
"extensions": [
"biomejs.biome",
"formulahendry.auto-rename-tag",
"bradlc.vscode-tailwindcss",
"stivo.tailwind-fold",
"streetsidesoftware.code-spell-checker",
"GitHub.copilot",
"ms-azuretools.vscode-docker",
"ms-python.python"
]
}
}
}
-48
View File
@@ -1,48 +0,0 @@
version: '3'
services:
app:
build:
context: .
dockerfile: Dockerfile
environment:
VSCODE_DEV_CONTAINER: true
volumes:
# Forwards the local Docker socket to the container.
- /var/run/docker.sock:/var/run/docker-host.sock
# Update this to wherever you want VS Code to mount the folder of your project
- ../..:/workspaces:cached
# Overrides default command so things don't shut down after the process ends.
# entrypoint: /usr/local/share/docker-init.sh
command: sleep infinity
postgres:
image: "postgres:15.2-alpine"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: verceldb
ports:
- "5480:5432"
pg_proxy:
image: ghcr.io/neondatabase/wsproxy:latest
environment:
APPEND_PORT: "postgres:5432"
ALLOW_ADDR_REGEX: ".*"
LOG_TRAFFIC: "true"
ports:
- "5481:80"
depends_on:
- postgres
localstack:
image: localstack/localstack:latest
environment:
SERVICES: s3
ports:
- 4566:4566
volumes:
- ../web/aws:/etc/localstack/init/ready.d
- ../web/aws:/app/web/aws
+1 -2
View File
@@ -1,3 +1,2 @@
__pycache__ __pycache__
.DS_Store .DS_Store
.vercel
+8 -1
View File
@@ -1,7 +1,14 @@
{ {
"recommendations": [ "recommendations": [
"DavidAnson.vscode-markdownlint", // markdown linting
"yzhang.markdown-all-in-one", // nicer markdown support
"esbenp.prettier-vscode", // prettier plugin
"dbaeumer.vscode-eslint", // eslint plugin
"bradlc.vscode-tailwindcss", // hinting / autocompletion for tailwind "bradlc.vscode-tailwindcss", // hinting / autocompletion for tailwind
"ban.spellright", // Spell check for docs "ban.spellright", // Spell check for docs
"biomejs.biome" // improved i18n DX "stripe.vscode-stripe", // stripe VSCode extension
"Prisma.prisma", // syntax|format|completion for prisma
"rebornix.project-snippets", // Share useful snippets between collaborators
"inlang.vs-code-extension" // improved i18n DX
] ]
} }
+7 -5
View File
@@ -1,16 +1,18 @@
{ {
"typescript.tsdk": "node_modules/typescript/lib", "typescript.tsdk": "node_modules/typescript/lib",
"editor.formatOnSave": true, "editor.formatOnSave": false,
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"quickfix.biome": "always" "source.fixAll.eslint": true
// "source.organizeImports.biome": "explicit"
}, },
"typescript.preferences.importModuleSpecifier": "non-relative", "typescript.preferences.importModuleSpecifier": "non-relative",
"spellright.language": ["en"], "spellright.language": ["en"],
"spellright.documentTypes": ["markdown", "typescript", "typescriptreact"], "spellright.documentTypes": ["markdown", "typescript", "typescriptreact"],
"tailwindCSS.experimental.classRegex": [ "tailwindCSS.experimental.classRegex": [
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"] [
] "cva\\(([^)]*)\\)",
"[\"'`]([^\"'`]*).*?[\"'`]"
]
],
// "eslint.workingDirectories": [ // "eslint.workingDirectories": [
// { "mode": "auto" } // { "mode": "auto" }
// ], // ],
-28
View File
@@ -1,28 +0,0 @@
{
"$schema": "./web/node_modules/@biomejs/biome/configuration_schema.json",
"organizeImports": {
"enabled": true
},
"formatter": {
"indentStyle": "space",
"indentWidth": 2,
"enabled": true
},
"linter": {
"enabled": false,
"rules": {
"recommended": true
}
},
"json": {
"parser": {
"allowComments": true
}
},
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true,
"defaultBranch": "main"
}
}
+1 -4
View File
@@ -1,8 +1,5 @@
MODAL_TOKEN_ID= MODAL_TOKEN_ID=
MODAL_TOKEN_SECRET= MODAL_TOKEN_SECRET=
CIVITAI_API_KEY=
# On production set to False # On production set to False
DEPLOY_TEST_FLAG=True DEPLOY_TEST_FLAG=True
CIVITAI_API_KEY=
PUBLIC_MODEL_VOLUME_NAME=
+1 -4
View File
@@ -42,9 +42,6 @@ fly secrets set MODAL_TOKEN_SECRET=
## To deploy ## To deploy
We have 2 `toml` files one for `production` and the other for `staging`
it will default to `staging` if you don't include the `-c` flag to choose your config file
``` ```
// model-builder/fly.toml // model-builder/fly.toml
app = <APP_NAME> app = <APP_NAME>
@@ -57,4 +54,4 @@ fly launch
if not, run this instead if not, run this instead
``` ```
fly deploy fly deploy
``` ```
-22
View File
@@ -1,22 +0,0 @@
# fly.toml app configuration file generated for modal-builder on 2024-01-03T22:29:34+08:00
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#
app = "modal-builder-production"
primary_region = "sea"
[build]
[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 0
processes = ["app"]
[[vm]]
cpu_kind = 'shared'
cpus = 1
memory_mb = 1024
+4 -9
View File
@@ -1,10 +1,10 @@
# fly.toml app configuration file generated for modal-builder-preview on 2024-01-25T09:26:31Z # fly.toml app configuration file generated for modal-builder on 2024-01-03T22:29:34+08:00
# #
# See https://fly.io/docs/reference/configuration/ for information about how to use this file. # See https://fly.io/docs/reference/configuration/ for information about how to use this file.
# #
app = 'modal-builder-preview' app = "modal-builder"
primary_region = 'sea' primary_region = "sea"
[build] [build]
@@ -14,9 +14,4 @@ primary_region = 'sea'
auto_stop_machines = true auto_stop_machines = true
auto_start_machines = true auto_start_machines = true
min_machines_running = 0 min_machines_running = 0
processes = ['app'] processes = ["app"]
[[vm]]
cpu_kind = 'shared'
cpus = 1
memory_mb = 1024
+22 -51
View File
@@ -47,8 +47,6 @@ machine_id_websocket_dict = {}
machine_id_status = {} machine_id_status = {}
fly_instance_id = os.environ.get('FLY_ALLOC_ID', 'local').split('-')[0] fly_instance_id = os.environ.get('FLY_ALLOC_ID', 'local').split('-')[0]
civitai_api_key = os.environ.get('FLY_ALLOC_ID', 'local')
public_model_volume_name = os.environ.get('PUBLIC_MODEL_VOLUME_NAME', 'local')
class FlyReplayMiddleware(BaseHTTPMiddleware): class FlyReplayMiddleware(BaseHTTPMiddleware):
@@ -143,7 +141,6 @@ def read_root():
class GitCustomNodes(BaseModel): class GitCustomNodes(BaseModel):
hash: str hash: str
disabled: bool disabled: bool
pip: Optional[List[str]] = None
class FileCustomNodes(BaseModel): class FileCustomNodes(BaseModel):
filename: str filename: str
@@ -179,7 +176,6 @@ class Item(BaseModel):
snapshot: Snapshot snapshot: Snapshot
models: List[Model] models: List[Model]
callback_url: str callback_url: str
model_volume_name: str
gpu: GPUType = Field(default=GPUType.T4) gpu: GPUType = Field(default=GPUType.T4)
@field_validator('gpu') @field_validator('gpu')
@@ -229,72 +225,53 @@ async def websocket_endpoint(websocket: WebSocket, machine_id: str):
# return {"Hello": "World"} # return {"Hello": "World"}
# definition based on web schema
class UploadType(str, Enum):
checkpoint = "checkpoint"
lora = "lora"
embedding = "embedding"
class UploadBody(BaseModel): class UploadBody(BaseModel):
download_url: str download_url: str
volume_name: str volume_name: str
volume_id: str volume_id: str
model_id: str # callback_url: str
upload_type: UploadType
callback_url: str
@app.post("/upload_volume")
# based on ComfyUI's model dir, and our mappings in ./src/template/data/extra_model_paths.yaml async def upload_checkpoint(body: UploadBody):
UPLOAD_TYPE_DIR_MAP = {
UploadType.checkpoint: "checkpoints",
UploadType.lora: "loras",
UploadType.embedding: "embeddings",
}
@app.post("/upload-volume")
async def upload_model(body: UploadBody):
global last_activity_time global last_activity_time
last_activity_time = time.time() last_activity_time = time.time()
logger.info(f"Extended inactivity time to {global_timeout}") logger.info(f"Extended inactivity time to {global_timeout}")
asyncio.create_task(upload_logic(body)) download_url = body.download_url
volume_name = body.volume_name
# check that this # callback_url = body.callback_url
return JSONResponse(status_code=200, content={"message": "Volume uploading", "build_machine_instance_id": fly_instance_id})
async def upload_logic(body: UploadBody):
folder_path = f"/app/builds/{body.volume_id}" folder_path = f"/app/builds/{body.volume_id}"
cp_process = await asyncio.subprocess.create_subprocess_exec("cp", "-r", "/app/src/volume-builder", folder_path) cp_process = await asyncio.subprocess.create_subprocess_exec("cp", "-r", "/app/src/volume-builder", folder_path)
await cp_process.wait() await cp_process.wait()
upload_path = UPLOAD_TYPE_DIR_MAP[body.upload_type] # Write the config file
config = { config = {
"volume_names": { "volume_names": {
body.volume_name: {"download_url": body.download_url, "folder_path": upload_path} volume_name: download_url
}, },
"volume_paths": { "paths": {
body.volume_name: f'/volumes/{uuid4()}' volume_name: f'/volumes/{uuid4()}'
}, },
"callback_url": body.callback_url,
"callback_body": {
"model_id": body.model_id,
"volume_id": body.volume_id,
"folder_path": upload_path,
},
"civitai_api_key": os.environ.get('CIVITAI_API_KEY')
} }
with open(f"{folder_path}/config.py", "w") as f:
f.write("config = " + json.dumps(config))
await asyncio.subprocess.create_subprocess_shell( await asyncio.subprocess.create_subprocess_shell(
f"modal run app.py", f"modal run app.py",
# stdout=asyncio.subprocess.PIPE,
# stderr=asyncio.subprocess.PIPE,
cwd=folder_path, cwd=folder_path,
env={**os.environ, "COLUMNS": "10000"} env={**os.environ, "COLUMNS": "10000"}
) )
with open(f"{folder_path}/config.py", "w") as f:
f.write("config = " + json.dumps(config))
# check that thi
return JSONResponse(status_code=200, content={"message": "Volume uploading", "build_machine_instance_id": fly_instance_id})
@app.post("/create") @app.post("/create")
async def create_machine(item: Item): async def create_machine(item: Item):
global last_activity_time global last_activity_time
@@ -379,19 +356,13 @@ async def build_logic(item: Item):
cp_process = await asyncio.subprocess.create_subprocess_exec("cp", "-r", "/app/src/template", folder_path) cp_process = await asyncio.subprocess.create_subprocess_exec("cp", "-r", "/app/src/template", folder_path)
await cp_process.wait() await cp_process.wait()
pip_modules = set()
for git_custom_node in item.snapshot.git_custom_nodes.values():
if git_custom_node.pip:
pip_modules.update(git_custom_node.pip)
# Write the config file # Write the config file
config = { config = {
"name": item.name, "name": item.name,
"deploy_test": os.environ.get("DEPLOY_TEST_FLAG", "False"), "deploy_test": os.environ.get("DEPLOY_TEST_FLAG", "False"),
"gpu": item.gpu, "gpu": item.gpu,
"public_model_volume": public_model_volume_name, "public_checkpoint_volume": "model-store",
"private_model_volume": item.model_volume_name, "private_checkpoint_volume": "private-model-store"
"pip": list(pip_modules)
} }
with open(f"{folder_path}/config.py", "w") as f: with open(f"{folder_path}/config.py", "w") as f:
f.write("config = " + json.dumps(config)) f.write("config = " + json.dumps(config))
+70 -92
View File
@@ -1,14 +1,14 @@
from config import config from config import config
import modal import modal
from modal import Image, Mount, web_endpoint, Stub, asgi_app, method, enter, exit from modal import Image, Mount, web_endpoint, Stub, asgi_app, Volume
import json import json
import urllib.request import urllib.request
import urllib.parse import urllib.parse
from pydantic import BaseModel from pydantic import BaseModel
from fastapi import FastAPI, Request, HTTPException from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse from fastapi.responses import HTMLResponse
from volume_setup import volumes from volume import volumes
from datetime import datetime
# deploy_test = False # deploy_test = False
import os import os
@@ -28,7 +28,6 @@ deploy_test = config["deploy_test"] == "True"
web_app = FastAPI() web_app = FastAPI()
print(config) print(config)
print("deploy_test ", deploy_test) print("deploy_test ", deploy_test)
print('volumes', volumes)
stub = Stub(name=config["name"]) stub = Stub(name=config["name"])
if not deploy_test: if not deploy_test:
@@ -53,8 +52,6 @@ if not deploy_test:
"cd /comfyui/custom_nodes/ComfyUI-Manager && pip install -r requirements.txt", "cd /comfyui/custom_nodes/ComfyUI-Manager && pip install -r requirements.txt",
"cd /comfyui/custom_nodes/ComfyUI-Manager && mkdir startup-scripts", "cd /comfyui/custom_nodes/ComfyUI-Manager && mkdir startup-scripts",
) )
.run_commands(f"cat /comfyui/server.py")
.run_commands(f"ls /comfyui/app")
# .run_commands( # .run_commands(
# # Install comfy deploy # # Install comfy deploy
# "cd /comfyui/custom_nodes && git clone https://github.com/BennyKok/comfyui-deploy.git", # "cd /comfyui/custom_nodes && git clone https://github.com/BennyKok/comfyui-deploy.git",
@@ -65,8 +62,6 @@ if not deploy_test:
.run_commands("chmod +x /start.sh") .run_commands("chmod +x /start.sh")
# Restore the custom nodes first # Restore the custom nodes first
.pip_install(config["pip"])
.copy_local_file(f"{current_directory}/data/restore_snapshot.py", "/") .copy_local_file(f"{current_directory}/data/restore_snapshot.py", "/")
.copy_local_file(f"{current_directory}/data/snapshot.json", "/comfyui/custom_nodes/ComfyUI-Manager/startup-scripts/restore-snapshot.json") .copy_local_file(f"{current_directory}/data/snapshot.json", "/comfyui/custom_nodes/ComfyUI-Manager/startup-scripts/restore-snapshot.json")
.run_commands("python restore_snapshot.py") .run_commands("python restore_snapshot.py")
@@ -158,106 +153,89 @@ image = Image.debian_slim()
target_image = image if deploy_test else dockerfile_image target_image = image if deploy_test else dockerfile_image
@stub.cls(image=target_image, gpu=config["gpu"] ,volumes=volumes, timeout=60 * 10, container_idle_timeout=60 * 5) @stub.function(image=target_image, gpu=config["gpu"]
class ComfyDeployRunner: ,volumes=volumes
)
def run(input: Input):
import subprocess
import time
# Make sure that the ComfyUI API is available
print(f"comfy-modal - check server")
@enter() command = ["python", "main.py",
def setup(self): "--disable-auto-launch", "--disable-metadata"]
import subprocess
import time
# Make sure that the ComfyUI API is available
print(f"comfy-modal - check server")
command = ["python", "main.py", server_process = subprocess.Popen(command, cwd="/comfyui")
"--disable-auto-launch", "--disable-metadata"]
self.server_process = subprocess.Popen(command, cwd="/comfyui") check_server(
f"http://{COMFY_HOST}",
COMFY_API_AVAILABLE_MAX_RETRIES,
COMFY_API_AVAILABLE_INTERVAL_MS,
)
check_server( job_input = input
f"http://{COMFY_HOST}",
COMFY_API_AVAILABLE_MAX_RETRIES,
COMFY_API_AVAILABLE_INTERVAL_MS,
)
@exit() # print(f"comfy-modal - got input {job_input}")
def cleanup(self, exc_type, exc_value, traceback):
self.server_process.terminate()
@method() # Queue the workflow
def run(self, input: Input): try:
data = json.dumps({ # job_input is the json input
"run_id": input.prompt_id, queued_workflow = queue_workflow_comfy_deploy(
"status": "started", job_input) # queue_workflow(workflow)
"time": datetime.now().isoformat() prompt_id = queued_workflow["prompt_id"]
}).encode('utf-8') print(f"comfy-modal - queued workflow with ID {prompt_id}")
req = urllib.request.Request(input.status_endpoint, data=data, method='POST') except Exception as e:
urllib.request.urlopen(req) import traceback
print(traceback.format_exc())
return {"error": f"Error queuing workflow: {str(e)}"}
job_input = input # Poll for completion
print(f"comfy-modal - wait until image generation is complete")
retries = 0
status = ""
try:
print("getting request")
while retries < COMFY_POLLING_MAX_RETRIES:
status_result = check_status(prompt_id=prompt_id)
# history = get_history(prompt_id)
try: # Exit the loop if we have found the history
queued_workflow = queue_workflow_comfy_deploy(job_input) # queue_workflow(workflow) # if prompt_id in history and history[prompt_id].get("outputs"):
prompt_id = queued_workflow["prompt_id"] # break
print(f"comfy-modal - queued workflow with ID {prompt_id}")
except Exception as e:
import traceback
print(traceback.format_exc())
return {"error": f"Error queuing workflow: {str(e)}"}
# Poll for completion # Exit the loop if we have found the status both success or failed
print(f"comfy-modal - wait until image generation is complete") if 'status' in status_result and (status_result['status'] == 'success' or status_result['status'] == 'failed'):
retries = 0 status = status_result['status']
status = "" print(status)
try: break
print("getting request")
while retries < COMFY_POLLING_MAX_RETRIES:
status_result = check_status(prompt_id=prompt_id)
# history = get_history(prompt_id)
# Exit the loop if we have found the history
# if prompt_id in history and history[prompt_id].get("outputs"):
# break
# Exit the loop if we have found the status both success or failed
if 'status' in status_result and (status_result['status'] == 'success' or status_result['status'] == 'failed'):
status = status_result['status']
print(status)
break
else:
# Wait before trying again
time.sleep(COMFY_POLLING_INTERVAL_MS / 1000)
retries += 1
else: else:
return {"error": "Max retries reached while waiting for image generation"} # Wait before trying again
except Exception as e: time.sleep(COMFY_POLLING_INTERVAL_MS / 1000)
return {"error": f"Error waiting for image generation: {str(e)}"} retries += 1
else:
return {"error": "Max retries reached while waiting for image generation"}
except Exception as e:
return {"error": f"Error waiting for image generation: {str(e)}"}
print(f"comfy-modal - Finished, turning off") print(f"comfy-modal - Finished, turning off")
server_process.terminate()
result = {"status": status} # Get the generated image and return it as URL in an AWS bucket or as base64
# images_result = process_output_images(history[prompt_id].get("outputs"), job["id"])
# result = {**images_result, "refresh_worker": REFRESH_WORKER}
result = {"status": status}
return result
print("Running remotely on Modal!")
return result
@web_app.post("/run") @web_app.post("/run")
async def post_run(request_input: RequestInput): async def bar(request_input: RequestInput):
# print(request_input)
if not deploy_test: if not deploy_test:
# print(request_input.input.prompt_id, request_input.input.status_endpoint) return run.remote(request_input.input)
data = json.dumps({ # pass
"run_id": request_input.input.prompt_id,
"status": "queued",
"time": datetime.now().isoformat()
}).encode('utf-8')
req = urllib.request.Request(request_input.input.status_endpoint, data=data, method='POST')
urllib.request.urlopen(req)
model = ComfyDeployRunner()
call = model.run.spawn(request_input.input)
# call = run.spawn()
return {"call_id": call.object_id}
return {"call_id": None}
@stub.function(image=image @stub.function(image=image
,volumes=volumes ,volumes=volumes
+3 -4
View File
@@ -1,8 +1,7 @@
config = { config = {
"name": "my-app", "name": "my-app",
"deploy_test": "False", "deploy_test": "True",
"gpu": "T4", "gpu": "T4",
"public_model_volume": "model-store", "public_checkpoint_volume": "model-store",
"private_model_volume": "private-model-store", "private_checkpoint_volume": "private-model-store"
"pip": []
} }
@@ -1,23 +1,30 @@
public: comfyui:
base_path: /public_models/ base_path: /extra_models/
checkpoints: checkpoints checkpoints: |
clip: clip checkpoints
clip_vision: clip_vision private_checkpoints
configs: configs clip: |
controlnet: controlnet clip
embeddings: embeddings private_clip
loras: loras clip_vision: |
upscale_models: upscale_models clip_vision
vae: vae private_clip_vision
configs: |
configs
private_configs
controlnet: |
controlnet
private_controlnet
embeddings: |
embeddings
private_embeddings
loras: |
loras
private_loras
upscale_models: |
upscale_models
private_upscale_models
vae: |
vae
private_vae
private:
base_path: /private_models/
checkpoints: checkpoints
clip: clip
clip_vision: clip_vision
configs: configs
controlnet: controlnet
embeddings: embeddings
loras: loras
upscale_models: upscale_models
vae: vae
@@ -0,0 +1,101 @@
"""
This is a standalone script to download models into a modal Volume using civitai
Example Usage
`modal run insert_models::insert_model --civitai-url https://civitai.com/models/36520/ghostmix`
This inserts an individual model from a civitai url
`modal run insert_models::insert_models_civitai_api`
This inserts a bunch of models based on the models retrieved by civitai
civitai's API reference https://github.com/civitai/civitai/wiki/REST-API-Reference
"""
import modal
import subprocess
import requests
import json
stub = modal.Stub()
# NOTE: volume name can be variable
volume = modal.Volume.persisted("rah")
model_store_path = "/vol/models"
MODEL_ROUTE = "models"
image = (
modal.Image.debian_slim().apt_install("wget").pip_install("requests")
)
@stub.function(volumes={model_store_path: volume}, image=image, timeout=50000, gpu=None)
def download_model(download_url):
print(download_url)
subprocess.run(["wget", download_url, "--content-disposition", "-P", model_store_path])
subprocess.run(["ls", "-la", model_store_path])
volume.commit()
# file is raw output from Civitai API https://github.com/civitai/civitai/wiki/REST-API-Reference
@stub.function()
def get_civitai_models(model_type: str, sort: str = "Highest Rated", page: int = 1):
"""Fetch models from CivitAI API based on type."""
try:
response = requests.get(f"https://civitai.com/api/v1/models", params={"types": model_type, "page": page, "sort": sort})
response.raise_for_status()
return response.json()
except requests.RequestException as e:
print(f"Error fetching models: {e}")
return None
@stub.function()
def get_civitai_model_url(civitai_url: str):
# Validate the URL
if civitai_url.startswith("https://civitai.com/api/"):
api_url = civitai_url
elif civitai_url.startswith("https://civitai.com/models/"):
try:
model_id = civitai_url.split("/")[4]
int(model_id)
except (IndexError, ValueError):
return None
api_url = f"https://civitai.com/api/v1/models/{model_id}"
else:
return "Error: URL must be from civitai.com and contain /models/"
response = requests.get(api_url)
# Check for successful response
if response.status_code != 200:
return f"Error: Unable to fetch data from {api_url}"
# Return the response data
return response.json()
@stub.local_entrypoint()
def insert_models_civitai_api(type: str = "Checkpoint", sort = "Highest Rated", page: int = 1):
civitai_models = get_civitai_models.local(type, sort, page)
if civitai_models:
for _ in download_model.map(map(lambda model: model['modelVersions'][0]['downloadUrl'], civitai_models['items'])):
pass
else:
print("Failed to retrieve models.")
@stub.local_entrypoint()
def insert_model(civitai_url: str):
if civitai_url.startswith("'https://civitai.com/api/download/models/"):
download_url = civitai_url
else:
civitai_model = get_civitai_model_url.local(civitai_url)
if civitai_model:
download_url = civitai_model['modelVersions'][0]['downloadUrl']
else:
return "invalid URL"
download_model.remote(download_url)
@stub.local_entrypoint()
def simple_download():
download_urls = ['https://civitai.com/api/download/models/119057', 'https://civitai.com/api/download/models/130090', 'https://civitai.com/api/download/models/31859', 'https://civitai.com/api/download/models/128713', 'https://civitai.com/api/download/models/179657', 'https://civitai.com/api/download/models/143906', 'https://civitai.com/api/download/models/9208', 'https://civitai.com/api/download/models/136078', 'https://civitai.com/api/download/models/134065', 'https://civitai.com/api/download/models/288775', 'https://civitai.com/api/download/models/95263', 'https://civitai.com/api/download/models/288982', 'https://civitai.com/api/download/models/87153', 'https://civitai.com/api/download/models/10638', 'https://civitai.com/api/download/models/263809', 'https://civitai.com/api/download/models/130072', 'https://civitai.com/api/download/models/117019', 'https://civitai.com/api/download/models/95256', 'https://civitai.com/api/download/models/197181', 'https://civitai.com/api/download/models/256915', 'https://civitai.com/api/download/models/118945', 'https://civitai.com/api/download/models/125843', 'https://civitai.com/api/download/models/179015', 'https://civitai.com/api/download/models/245598', 'https://civitai.com/api/download/models/223670', 'https://civitai.com/api/download/models/90072', 'https://civitai.com/api/download/models/290817', 'https://civitai.com/api/download/models/154097', 'https://civitai.com/api/download/models/143497', 'https://civitai.com/api/download/models/5637']
for _ in download_model.map(download_urls):
pass
@@ -45,12 +45,12 @@ for package in packages:
response = requests.request("POST", f"{root_url}/customnode/install", json=package, headers=headers) response = requests.request("POST", f"{root_url}/customnode/install", json=package, headers=headers)
print(response.text) print(response.text)
with open('models.json') as f: # with open('models.json') as f:
models = json.load(f) # models = json.load(f)
#
for model in models: # for model in models:
response = requests.request("POST", f"{root_url}/model/install", json=model, headers=headers) # response = requests.request("POST", f"{root_url}/model/install", json=model, headers=headers)
print(response.text) # print(response.text)
# Close the server # Close the server
server_process.terminate() server_process.terminate()
@@ -1,10 +1,5 @@
{ {
"comfyui": "d0165d819afe76bd4e6bdd710eb5f3e571b6a804", "comfyui": "d0165d819afe76bd4e6bdd710eb5f3e571b6a804",
"git_custom_nodes": { "git_custom_nodes": {},
"https://github.com/BennyKok/comfyui-deploy.git": { "file_custom_nodes": []
"hash": "a838cb7ad425e5652c3931fbafdc886b53c48a22", }
"disabled": false
}
},
"file_custom_nodes": []
}
@@ -0,0 +1,10 @@
import modal
from config import config
public_model_volume = modal.Volume.persisted(config["public_checkpoint_volume"])
private_volume = modal.Volume.persisted(config["private_checkpoint_volume"])
BASEMODEL_DIR = "/extra_models/"
MODEL_DIR = BASEMODEL_DIR + "checkpoints"
PRIVATE_MODEL_DIR = BASEMODEL_DIR + "private_checkpoints"
volumes = {MODEL_DIR: public_model_volume, PRIVATE_MODEL_DIR: private_volume}
@@ -1,9 +0,0 @@
import modal
from config import config
public_model_volume = modal.Volume.persisted(config["public_model_volume"])
private_volume = modal.Volume.persisted(config["private_model_volume"])
PUBLIC_BASEMODEL_DIR = "/public_models"
PRIVATE_BASEMODEL_DIR = "/private_models"
volumes = {PUBLIC_BASEMODEL_DIR: public_model_volume, PRIVATE_BASEMODEL_DIR: private_volume}
+12 -41
View File
@@ -2,7 +2,6 @@ import modal
from config import config from config import config
import os import os
import subprocess import subprocess
from pprint import pprint
stub = modal.Stub() stub = modal.Stub()
@@ -22,53 +21,25 @@ def create_volumes(volume_names, paths):
return path_to_vol return path_to_vol
vol_name_to_links = config["volume_names"] vol_name_to_links = config["volume_names"]
vol_name_to_path = config["volume_paths"] vol_name_to_path = config["paths"]
callback_url = config["callback_url"]
callback_body = config["callback_body"]
civitai_key = config["civitai_api_key"]
volumes = create_volumes(vol_name_to_links, vol_name_to_path) volumes = create_volumes(vol_name_to_links, vol_name_to_path)
image = ( image = (
modal.Image.debian_slim().apt_install("wget").pip_install("requests") modal.Image.debian_slim().apt_install("wget").pip_install("requests")
) )
# download config { "download_url": "", "folder_path": ""} print(vol_name_to_links)
timeout=5000 print(vol_name_to_path)
@stub.function(volumes=volumes, image=image, timeout=timeout, gpu=None) print(volumes)
def download_model(volume_name, download_config):
import requests
download_url = download_config["download_url"]
folder_path = download_config["folder_path"]
volume_base_path = vol_name_to_path[volume_name] @stub.function(volumes=volumes, image=image, timeout=5000, gpu=None)
model_store_path = os.path.join(volume_base_path, folder_path) def download_model(volume_name, download_url):
modified_download_url = download_url + ("&" if "?" in download_url else "?") + "token=" + civitai_key model_store_path = vol_name_to_path[volume_name]
print('downloading', modified_download_url) subprocess.run(["wget", download_url, "--content-disposition", "-P", model_store_path])
subprocess.run(["wget", modified_download_url , "--content-disposition", "-P", model_store_path])
subprocess.run(["ls", "-la", volume_base_path])
subprocess.run(["ls", "-la", model_store_path]) subprocess.run(["ls", "-la", model_store_path])
volumes[volume_base_path].commit() volumes[model_store_path].commit()
status = {"status": "success"}
requests.post(callback_url, json={**status, **callback_body})
print(f"finished! sending to {callback_url}")
pprint({**status, **callback_body})
@stub.local_entrypoint() @stub.local_entrypoint()
def simple_download(): def simple_download():
import requests print(vol_name_to_links)
try: print([(vol_name, link) for vol_name,link in vol_name_to_links.items()])
list(download_model.starmap([(vol_name, link) for vol_name,link in vol_name_to_links.items()])) list(download_model.starmap([(vol_name, link) for vol_name,link in vol_name_to_links.items()]))
except modal.exception.FunctionTimeoutError as e:
status = {"status": "failed", "error_logs": f"{str(e)}", "timeout": timeout}
requests.post(callback_url, json={**status, **callback_body})
print(f"finished! sending to {callback_url}")
pprint({**status, **callback_body})
except Exception as e:
status = {"status": "failed", "error_logs": str(e)}
requests.post(callback_url, json={**status, **callback_body})
print(f"finished! sending to {callback_url}")
pprint({**status, **callback_body})
@@ -1,18 +1,8 @@
config = { config = {
"volume_names": { "volume_names": {
"user4": { "test": "https://pub-6230db03dc3a4861a9c3e55145ceda44.r2.dev/openpose-pose (1).png"
"download_url": "https://civitai.com/api/download/models/11745",
"folder_path": "checkpoints"
}
}, },
"volume_paths": { "paths": {
"user4": "/volumes/something", "test": "/volumes/something"
}, }
"callback_url": "",
"callback_body": {
"model_id": "",
"volume_id": "",
"folder_path": "checkpoints",
},
"civitai_api_key": "",
} }
-68
View File
@@ -1,68 +0,0 @@
import folder_paths
from PIL import Image, ImageOps
import numpy as np
import torch
import folder_paths
from tqdm import tqdm
class ComfyUIDeployExternalCheckpoint:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input_id": (
"STRING",
{"multiline": False, "default": "input_checkpoint"},
),
},
"optional": {
"default_checkpoint_name": (folder_paths.get_filename_list("checkpoints"), ),
}
}
RETURN_TYPES = (folder_paths.get_filename_list("checkpoints"),)
RETURN_NAMES = ("path",)
FUNCTION = "run"
CATEGORY = "deploy"
def run(self, input_id, default_checkpoint_name=None):
import requests
import os
import uuid
if input_id and input_id.startswith('http'):
unique_filename = str(uuid.uuid4()) + ".safetensors"
print(unique_filename)
print(folder_paths.folder_names_and_paths["checkpoints"][0][0])
destination_path = os.path.join(
folder_paths.folder_names_and_paths["checkpoints"][0][0], unique_filename)
print(destination_path)
print("Downloading external checkpoint - " +
input_id + " to " + destination_path)
response = requests.get(
input_id, headers={'User-Agent': 'Mozilla/5.0'}, allow_redirects=True, stream=True)
file_size = int(response.headers.get('Content-Length', 0))
chunk = 1
chunk_size = 1024
num_bars = int(file_size / chunk_size)
with open(destination_path, 'wb') as out_file:
for chunk in tqdm(
response.iter_content(chunk_size=chunk_size),
total=num_bars,
unit='KB',
desc="Downloading",
leave=True # leave=True to keep progress bars
):
out_file.write(chunk)
return (unique_filename,)
else:
return (default_checkpoints_name,)
NODE_CLASS_MAPPINGS = {
"ComfyUIDeployExternalCheckpoint": ComfyUIDeployExternalCheckpoint}
NODE_DISPLAY_NAME_MAPPINGS = {
"ComfyUIDeployExternalCheckpoint": "External Checkpoint (ComfyUI Deploy)"}
+1 -4
View File
@@ -203,10 +203,7 @@ async def send_json_override(self, event, data, sid=None):
prompt_id = data.get('prompt_id') prompt_id = data.get('prompt_id')
# now we send everything # now we send everything
await asyncio.wait([ await asyncio.wait([send(event, data), self.send_json_original(event, data, sid)])
asyncio.create_task(send(event, data)),
asyncio.create_task(self.send_json_original(event, data, sid))
])
if event == 'execution_start': if event == 'execution_start':
update_run(prompt_id, Status.RUNNING) update_run(prompt_id, Status.RUNNING)
+43 -230
View File
@@ -9,65 +9,6 @@ const ext = {
init(app) { init(app) {
addButton(); addButton();
const queryParams = new URLSearchParams(window.location.search);
const workflow_version_id = queryParams.get("workflow_version_id");
const auth_token = queryParams.get("auth_token");
const org_display = queryParams.get("org_display");
const origin = queryParams.get("origin");
const data = getData();
let endpoint = data.endpoint;
let apiKey = data.apiKey;
// If there is auth token override it
if (auth_token) {
apiKey = auth_token;
endpoint = origin;
saveData({
displayName: org_display,
endpoint: origin,
apiKey: auth_token,
displayName: org_display,
environment: "cloud",
});
localStorage.setItem("comfy_deploy_env", "cloud");
}
if (!workflow_version_id) {
console.error("No workflow_version_id provided in query parameters.");
} else {
loadingDialog.showLoading(
"Loading workflow from " + org_display,
"Please wait...",
);
fetch(endpoint + "/api/workflow-version/" + workflow_version_id, {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + apiKey,
},
})
.then(async (res) => {
const data = await res.json();
const { workflow, error } = data;
if (error) {
infoDialog.showMessage("Unable to load this workflow", error);
return;
}
/** @type {LGraph} */
app.loadGraphData(workflow);
})
.catch((e) => infoDialog.showMessage("Error", e.message))
.finally(() => {
loadingDialog.close();
window.history.replaceState(
{},
document.title,
window.location.pathname,
);
});
}
}, },
registerCustomNodes() { registerCustomNodes() {
@@ -179,7 +120,7 @@ function addButton() {
const graph = app.graph; const graph = app.graph;
const snapshot = await fetch("/snapshot/get_current").then((x) => x.json()); const snapshot = await fetch("/snapshot/get_current").then((x) => x.json());
// console.log(snapshot); console.log(snapshot);
if (!snapshot) { if (!snapshot) {
showError( showError(
@@ -213,7 +154,7 @@ function addButton() {
const deployMetaNode = deployMeta[0]; const deployMetaNode = deployMeta[0];
// console.log(deployMetaNode); console.log(deployMetaNode);
const workflow_name = deployMetaNode.widgets[0].value; const workflow_name = deployMetaNode.widgets[0].value;
const workflow_id = deployMetaNode.widgets[1].value; const workflow_id = deployMetaNode.widgets[1].value;
@@ -227,43 +168,38 @@ function addButton() {
// const endpoint = localStorage.getItem("endpoint") ?? ""; // const endpoint = localStorage.getItem("endpoint") ?? "";
// const apiKey = localStorage.getItem("apiKey"); // const apiKey = localStorage.getItem("apiKey");
const { endpoint, apiKey, displayName } = getData(); const { endpoint, apiKey } = getData();
if (!endpoint || !apiKey || apiKey === "" || endpoint === "") { if (!endpoint || !apiKey || apiKey === "" || endpoint === "") {
configDialog.show(); configDialog.show();
return; return;
} }
const ok = await confirmDialog.confirm( const ok = await confirmDialog.confirm("Confirm deployment", "A new version will be deployed, are you conform?")
"Confirm deployment -> " + displayName,
"A new version will be deployed, are you conform?",
);
if (!ok) return; if (!ok) return;
title.innerText = "Deploying..."; title.innerText = "Deploying...";
title.style.color = "orange"; title.style.color = "orange";
// console.log(prompt); console.log(prompt);
// TODO trim the ending / from endpoint is there is // TODO trim the ending / from endpoint is there is
if (endpoint.endsWith("/")) { if (endpoint.endsWith("/")) {
endpoint = endpoint.slice(0, -1); endpoint = endpoint.slice(0, -1);
} }
const apiRoute = endpoint + "/api/workflow"; const apiRoute = endpoint + "/api/upload";
// const userId = apiKey // const userId = apiKey
try { try {
const body = {
workflow_name,
workflow_id,
workflow: prompt.workflow,
workflow_api: prompt.output,
snapshot: snapshot,
};
console.log(body);
let data = await fetch(apiRoute, { let data = await fetch(apiRoute, {
method: "POST", method: "POST",
body: JSON.stringify(body), body: JSON.stringify({
workflow_name,
workflow_id,
workflow: prompt.workflow,
workflow_api: prompt.output,
snapshot: snapshot,
}),
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
Authorization: "Bearer " + apiKey, Authorization: "Bearer " + apiKey,
@@ -339,16 +275,14 @@ export class InfoDialog extends ComfyDialog {
this.element.classList.add("comfy-normal-modal"); this.element.classList.add("comfy-normal-modal");
this.element.style.paddingBottom = "20px"; this.element.style.paddingBottom = "20px";
} }
button = undefined;
createButtons() { createButtons() {
this.button = $el("button", { return [
type: "button", $el("button", {
textContent: "Close", type: "button",
onclick: () => this.close(), textContent: "Close",
}); onclick: () => this.close(),
return [this.button]; }),
];
} }
close() { close() {
@@ -367,69 +301,6 @@ export class InfoDialog extends ComfyDialog {
this.element.style.display = "flex"; this.element.style.display = "flex";
this.element.style.zIndex = 1001; this.element.style.zIndex = 1001;
} }
showMessage(title, message) {
this.show(`
<div style="width: 400px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
<h3 style="margin: 0px;">${title}</h3>
<label>
${message}
</label>
</div>
`);
}
loadingIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><g fill="none" stroke="#888888" stroke-linecap="round" stroke-width="2"><path stroke-dasharray="60" stroke-dashoffset="60" stroke-opacity=".3" d="M12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3Z"><animate fill="freeze" attributeName="stroke-dashoffset" dur="1.3s" values="60;0"/></path><path stroke-dasharray="15" stroke-dashoffset="15" d="M12 3C16.9706 3 21 7.02944 21 12"><animate fill="freeze" attributeName="stroke-dashoffset" dur="0.3s" values="15;0"/><animateTransform attributeName="transform" dur="1.5s" repeatCount="indefinite" type="rotate" values="0 12 12;360 12 12"/></path></g></svg>`;
showLoading(title, message) {
this.show(`
<div style="width: 400px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
<h3 style="margin: 0px; display: flex; align-items: center; justify-content: center;">${title} ${this.loadingIcon}</h3>
<label>
${message}
</label>
</div>
`);
}
}
export class LoadingDialog extends ComfyDialog {
constructor() {
super();
this.element.classList.add("comfy-normal-modal");
// this.element.style.paddingBottom = "20px";
}
createButtons() {
return [];
}
close() {
this.element.style.display = "none";
}
show(html) {
this.textElement.style["white-space"] = "normal";
this.textElement.style.color = "white";
this.textElement.style.marginTop = "0px";
if (typeof html === "string") {
this.textElement.innerHTML = html;
} else {
this.textElement.replaceChildren(html);
}
this.element.style.display = "flex";
this.element.style.zIndex = 1001;
}
loadingIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><g fill="none" stroke="#888888" stroke-linecap="round" stroke-width="2"><path stroke-dasharray="60" stroke-dashoffset="60" stroke-opacity=".3" d="M12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3Z"><animate fill="freeze" attributeName="stroke-dashoffset" dur="1.3s" values="60;0"/></path><path stroke-dasharray="15" stroke-dashoffset="15" d="M12 3C16.9706 3 21 7.02944 21 12"><animate fill="freeze" attributeName="stroke-dashoffset" dur="0.3s" values="15;0"/><animateTransform attributeName="transform" dur="1.5s" repeatCount="indefinite" type="rotate" values="0 12 12;360 12 12"/></path></g></svg>`;
showLoading(title, message) {
this.show(`
<div style="width: 400px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
<h3 style="margin: 0px; display: flex; align-items: center; justify-content: center; gap: 4px;">${title} ${this.loadingIcon}</h3>
</div>
`);
}
} }
export class InputDialog extends InfoDialog { export class InputDialog extends InfoDialog {
@@ -496,6 +367,7 @@ export class InputDialog extends InfoDialog {
} }
} }
export class ConfirmDialog extends InfoDialog { export class ConfirmDialog extends InfoDialog {
callback = undefined; callback = undefined;
@@ -557,15 +429,9 @@ export class ConfirmDialog extends InfoDialog {
} }
export const inputDialog = new InputDialog(); export const inputDialog = new InputDialog();
export const loadingDialog = new LoadingDialog();
export const infoDialog = new InfoDialog(); export const infoDialog = new InfoDialog();
export const confirmDialog = new ConfirmDialog(); export const confirmDialog = new ConfirmDialog();
/**
* Retrieves deployment data from local storage or defaults.
* @param {string} [environment] - The environment to get the data for.
* @returns {{endpoint: string, apiKey: string, displayName: string, environment?: string}} The deployment data.
*/
function getData(environment) { function getData(environment) {
const deployOption = const deployOption =
environment || localStorage.getItem("comfy_deploy_env") || "cloud"; environment || localStorage.getItem("comfy_deploy_env") || "cloud";
@@ -588,21 +454,8 @@ function getData(environment) {
}; };
} }
/**
* Retrieves deployment data from local storage or defaults.
* @param {{endpoint: string, apiKey: string, displayName: string, environment?: string}} [data] - The environment to get the data for.
*/
function saveData(data) {
localStorage.setItem(
"comfy_deploy_env_data_" + data.environment,
JSON.stringify(data),
);
}
export class ConfigDialog extends ComfyDialog { export class ConfigDialog extends ComfyDialog {
container = null; container = null;
poll = null;
timeout = null;
constructor() { constructor() {
super(); super();
@@ -645,24 +498,22 @@ export class ConfigDialog extends ComfyDialog {
close() { close() {
this.element.style.display = "none"; this.element.style.display = "none";
clearInterval(this.poll);
clearTimeout(this.timeout);
} }
save(api_key, displayName) { save() {
if (!displayName) displayName = getData().displayName;
const deployOption = this.container.querySelector("#deployOption").value; const deployOption = this.container.querySelector("#deployOption").value;
localStorage.setItem("comfy_deploy_env", deployOption); localStorage.setItem("comfy_deploy_env", deployOption);
const endpoint = this.container.querySelector("#endpoint").value; const endpoint = this.container.querySelector("#endpoint").value;
const apiKey = api_key ?? this.container.querySelector("#apiKey").value; const apiKey = this.container.querySelector("#apiKey").value;
saveData({ const data = {
endpoint, endpoint,
apiKey, apiKey,
displayName, };
environment: deployOption, localStorage.setItem(
}); "comfy_deploy_env_data_" + deployOption,
JSON.stringify(data),
);
this.close(); this.close();
} }
@@ -676,69 +527,31 @@ export class ConfigDialog extends ComfyDialog {
<h3 style="margin: 0px;">Comfy Deploy Config</h3> <h3 style="margin: 0px;">Comfy Deploy Config</h3>
<label style="color: white; width: 100%;"> <label style="color: white; width: 100%;">
<select id="deployOption" style="margin: 8px 0px; width: 100%; height:30px; box-sizing: border-box;" > <select id="deployOption" style="margin: 8px 0px; width: 100%; height:30px; box-sizing: border-box;" >
<option value="cloud" ${data.environment === "cloud" ? "selected" : ""}>Cloud</option> <option value="cloud" ${
<option value="local" ${data.environment === "local" ? "selected" : ""}>Local</option> data.environment === "cloud" ? "selected" : ""
}>Cloud</option>
<option value="local" ${
data.environment === "local" ? "selected" : ""
}>Local</option>
</select> </select>
</label> </label>
<label style="color: white; width: 100%;"> <label style="color: white; width: 100%;">
Endpoint: Endpoint:
<input id="endpoint" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;" type="text" value="${data.endpoint <input id="endpoint" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;" type="text" value="${
}"> data.endpoint
}">
</label> </label>
<label style="color: white;"> <label style="color: white;">
API Key: ${data.displayName ?? ""} API Key:
<input id="apiKey" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;" type="password" value="${data.apiKey <input id="apiKey" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;" type="password" value="${
}"> data.apiKey
<button id="loginButton" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;"> }">
${data.apiKey ? "Re-login with ComfyDeploy" : "Login with ComfyDeploy"
}
</button>
</label> </label>
</div> </div>
`; `;
const button = this.container.querySelector("#loginButton");
button.onclick = () => {
const uuid =
Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15);
window.open(data.endpoint + "/auth-request/" + uuid, "_blank");
this.timeout = setTimeout(() => {
clearInterval(poll);
infoDialog.showMessage(
"Timeout",
"Wait too long for the response, please try re-login",
);
}, 30000); // Stop polling after 30 seconds
this.poll = setInterval(() => {
fetch(data.endpoint + "/api/auth-response/" + uuid)
.then((response) => response.json())
.then((json) => {
if (json.api_key) {
this.save(json.api_key, json.name);
this.container.querySelector("#apiKey").value = json.api_key;
infoDialog.show();
clearInterval(this.poll);
clearTimeout(this.timeout);
infoDialog.showMessage(
"Authenticated",
"You will be able to upload workflow to " + json.name,
);
}
})
.catch((error) => {
console.error("Error:", error);
clearInterval(this.poll);
clearTimeout(this.timeout);
infoDialog.showMessage("Error", error);
});
}, 2000);
};
const apiKeyInput = this.container.querySelector("#apiKey"); const apiKeyInput = this.container.querySelector("#apiKey");
apiKeyInput.addEventListener("paste", (e) => { apiKeyInput.addEventListener("paste", function (e) {
e.stopPropagation(); e.stopPropagation();
}); });
-11
View File
@@ -20,14 +20,3 @@ PLAUSIBLE_DOMAIN=
NEXT_PUBLIC_POSTHOG_KEY="your-api-key" NEXT_PUBLIC_POSTHOG_KEY="your-api-key"
NEXT_PUBLIC_POSTHOG_HOST="your-ph-address" NEXT_PUBLIC_POSTHOG_HOST="your-ph-address"
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/auth/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/auth/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/
STRIPE_API_KEY="sk_test_"
STRIPE_PR_PRO="price_"
STRIPE_PR_ENTERPRISE="price_"
STRIPE_PR_API="price_"
STRIPE_WEBHOOK_SECRET="whsec_"
+6
View File
@@ -0,0 +1,6 @@
node_modules
**/node_modules
**/.next
**/public
packages/prisma/zod
apps/web/public/embed
+95
View File
@@ -0,0 +1,95 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: [
// "plugin:playwright/playwright-test",
"next",
// "next/core-web-vitals",
"plugin:prettier/recommended",
// "turbo",
// "plugin:you-dont-need-lodash-underscore/compatible-warn",
],
plugins: ["unused-imports"],
parserOptions: {
tsconfigRootDir: __dirname,
project: ["./tsconfig.json"],
// project: ["./apps/*/tsconfig.json", "./packages/*/tsconfig.json"],
},
settings: {
next: {
// rootDir: ["apps/*/", "packages/*/"],
rootDir: ["src"],
},
},
rules: {
"@next/next/no-img-element": "off",
"@next/next/no-html-link-for-pages": "off",
"jsx-a11y/role-supports-aria-props": "off", // @see https://github.com/vercel/next.js/issues/27989#issuecomment-897638654
// "playwright/no-page-pause": "error",
"react/jsx-curly-brace-presence": [
"error",
{ props: "never", children: "never" },
],
"react/self-closing-comp": ["error", { component: true, html: true }],
"@typescript-eslint/no-unused-vars": [
"warn",
{
vars: "all",
varsIgnorePattern: "^_",
args: "after-used",
argsIgnorePattern: "^_",
destructuredArrayIgnorePattern: "^_",
},
],
"unused-imports/no-unused-imports": "error",
"no-restricted-imports": [
"error",
{
patterns: ["lodash"],
},
],
"prefer-template": "error",
},
overrides: [
{
files: ["*.ts", "*.tsx"],
extends: [
"plugin:@typescript-eslint/recommended",
// "plugin:@calcom/eslint/recommended",
],
plugins: [
"@typescript-eslint",
// "@calcom/eslint"
],
parser: "@typescript-eslint/parser",
rules: {
"@typescript-eslint/consistent-type-imports": [
"error",
{
prefer: "type-imports",
// TODO: enable this once prettier supports it
// fixStyle: "inline-type-imports",
fixStyle: "separate-type-imports",
disallowTypeAnnotations: false,
},
],
},
// overrides: [
// {
// files: ["**/playwright/**/*.{tsx,ts}"],
// rules: {
// "@typescript-eslint/no-unused-vars": "off",
// "no-undef": "off",
// },
// },
// ],
},
// {
// files: ["**/playwright/**/*.{js,jsx}"],
// rules: {
// "@typescript-eslint/no-unused-vars": "off",
// "no-undef": "off",
// },
// },
],
};
BIN
View File
Binary file not shown.
-1
View File
@@ -1 +0,0 @@
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "started_at" timestamp;
@@ -5,7 +5,7 @@ EXCEPTION
END $$; END $$;
--> statement-breakpoint --> statement-breakpoint
DO $$ BEGIN DO $$ BEGIN
CREATE TYPE "resource_upload" AS ENUM('started', 'success', 'failed'); CREATE TYPE "resource_upload" AS ENUM('started', 'failed', 'succeded');
EXCEPTION EXCEPTION
WHEN duplicate_object THEN null; WHEN duplicate_object THEN null;
END $$; END $$;
@@ -17,7 +17,6 @@ CREATE TABLE IF NOT EXISTS "comfyui_deploy"."checkpoints" (
"description" text, "description" text,
"checkpoint_volume_id" uuid NOT NULL, "checkpoint_volume_id" uuid NOT NULL,
"model_name" text, "model_name" text,
"folder_path" text,
"civitai_id" text, "civitai_id" text,
"civitai_version_id" text, "civitai_version_id" text,
"civitai_url" text, "civitai_url" text,
@@ -30,7 +29,6 @@ CREATE TABLE IF NOT EXISTS "comfyui_deploy"."checkpoints" (
"status" "resource_upload" DEFAULT 'started' NOT NULL, "status" "resource_upload" DEFAULT 'started' NOT NULL,
"upload_machine_id" text, "upload_machine_id" text,
"upload_type" "model_upload_type" NOT NULL, "upload_type" "model_upload_type" NOT NULL,
"error_log" text,
"created_at" timestamp DEFAULT now() NOT NULL, "created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL "updated_at" timestamp DEFAULT now() NOT NULL
); );
@@ -52,7 +50,7 @@ EXCEPTION
END $$; END $$;
--> statement-breakpoint --> statement-breakpoint
DO $$ BEGIN DO $$ BEGIN
ALTER TABLE "comfyui_deploy"."checkpoints" ADD CONSTRAINT "checkpoints_checkpoint_volume_id_checkpoint_volume_id_fk" FOREIGN KEY ("checkpoint_volume_id") REFERENCES "comfyui_deploy"."checkpoint_volume"("id") ON DELETE cascade ON UPDATE no action; ALTER TABLE "comfyui_deploy"."checkpoints" ADD CONSTRAINT "checkpoints_checkpoint_volume_id_workflow_runs_id_fk" FOREIGN KEY ("checkpoint_volume_id") REFERENCES "comfyui_deploy"."workflow_runs"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION EXCEPTION
WHEN duplicate_object THEN null; WHEN duplicate_object THEN null;
END $$; END $$;
+2
View File
@@ -0,0 +1,2 @@
ALTER TYPE "resource_upload" ADD VALUE 'error';--> statement-breakpoint
ALTER TABLE "comfyui_deploy"."checkpoints" ADD COLUMN "build_log" text;
-2
View File
@@ -1,2 +0,0 @@
ALTER TABLE "comfyui_deploy"."deployments" ADD COLUMN "share_slug" text;--> statement-breakpoint
ALTER TABLE "comfyui_deploy"."deployments" ADD CONSTRAINT "deployments_share_slug_unique" UNIQUE("share_slug");
-8
View File
@@ -1,8 +0,0 @@
CREATE TABLE IF NOT EXISTS "comfyui_deploy"."auth_requests" (
"request_id" text PRIMARY KEY NOT NULL,
"user_id" text,
"org_id" text,
"api_hash" text,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL
);
-1
View File
@@ -1 +0,0 @@
ALTER TABLE "comfyui_deploy"."auth_requests" ADD COLUMN "expired_date" timestamp;
@@ -1,14 +0,0 @@
CREATE TABLE IF NOT EXISTS "comfyui_deploy"."user_usage" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"org_id" text,
"user_id" text NOT NULL,
"usage_time" real DEFAULT 0 NOT NULL,
"created_at" timestamp DEFAULT now() NOT NULL,
"ended_at" timestamp DEFAULT now() NOT NULL
);
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "comfyui_deploy"."user_usage" ADD CONSTRAINT "user_usage_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "comfyui_deploy"."users"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
-22
View File
@@ -1,22 +0,0 @@
DO $$ BEGIN
CREATE TYPE "subscription_plan" AS ENUM('basic', 'pro', 'enterprise');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
CREATE TYPE "subscription_plan_status" AS ENUM('active', 'deleted', 'paused');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "comfyui_deploy"."subscription_status" (
"stripe_customer_id" text PRIMARY KEY NOT NULL,
"user_id" text,
"org_id" text,
"plan" "subscription_plan" NOT NULL,
"status" "subscription_plan_status" NOT NULL,
"subscription_plan_id" text,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL
);
-3
View File
@@ -1,3 +0,0 @@
ALTER TABLE "comfyui_deploy"."subscription_status" RENAME COLUMN "subscription_plan_id" TO "subscription_id";--> statement-breakpoint
ALTER TABLE "comfyui_deploy"."subscription_status" ADD COLUMN "subscription_item_plan_id" text;--> statement-breakpoint
ALTER TABLE "comfyui_deploy"."subscription_status" ADD COLUMN "subscription_item_api_id" text;
-1
View File
@@ -1 +0,0 @@
ALTER TABLE "comfyui_deploy"."subscription_status" ADD COLUMN "cancel_at_period_end" boolean DEFAULT false;
-2
View File
@@ -1,2 +0,0 @@
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "user_id" text;--> statement-breakpoint
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "org_id" text;
-1
View File
@@ -1 +0,0 @@
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "gpu" "machine_gpu";
-1
View File
@@ -1 +0,0 @@
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "machine_type" "machine_type";
-33
View File
@@ -1,33 +0,0 @@
DO $$ BEGIN
CREATE TYPE "model_type" AS ENUM('checkpoint', 'lora', 'embedding', 'vae');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
ALTER TABLE "comfyui_deploy"."checkpoints" RENAME TO "models";--> statement-breakpoint
ALTER TABLE "comfyui_deploy"."checkpoint_volume" RENAME TO "user_volume";--> statement-breakpoint
ALTER TABLE "comfyui_deploy"."models" RENAME COLUMN "checkpoint_volume_id" TO "user_volume_id";--> statement-breakpoint
ALTER TABLE "comfyui_deploy"."models" DROP CONSTRAINT "checkpoints_user_id_users_id_fk";
--> statement-breakpoint
ALTER TABLE "comfyui_deploy"."models" DROP CONSTRAINT "checkpoints_checkpoint_volume_id_checkpoint_volume_id_fk";
--> statement-breakpoint
ALTER TABLE "comfyui_deploy"."user_volume" DROP CONSTRAINT "checkpoint_volume_user_id_users_id_fk";
--> statement-breakpoint
ALTER TABLE "comfyui_deploy"."models" ADD COLUMN "model_type" "model_type" DEFAULT 'checkpoint' NOT NULL;--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "comfyui_deploy"."models" ADD CONSTRAINT "models_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "comfyui_deploy"."users"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "comfyui_deploy"."models" ADD CONSTRAINT "models_user_volume_id_user_volume_id_fk" FOREIGN KEY ("user_volume_id") REFERENCES "comfyui_deploy"."user_volume"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "comfyui_deploy"."user_volume" ADD CONSTRAINT "user_volume_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "comfyui_deploy"."users"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
@@ -1 +0,0 @@
ALTER TABLE "comfyui_deploy"."models" ALTER COLUMN "is_public" SET DEFAULT true;
-3
View File
@@ -1,3 +0,0 @@
ALTER TYPE "workflow_run_status" ADD VALUE 'started';--> statement-breakpoint
ALTER TYPE "workflow_run_status" ADD VALUE 'queued';--> statement-breakpoint
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "queued_at" timestamp;
+249 -7
View File
@@ -1,5 +1,5 @@
{ {
"id": "1ca4fdb7-c0c4-4c39-8b47-f40282293da0", "id": "4d5b29d0-848f-4c2e-a2cd-2932f1fa38c6",
"prevId": "db06ea66-92c2-4ebe-93c1-6cb8a90ccd8b", "prevId": "db06ea66-92c2-4ebe-93c1-6cb8a90ccd8b",
"version": "5", "version": "5",
"dialect": "pg", "dialect": "pg",
@@ -88,6 +88,238 @@
} }
} }
}, },
"checkpoints": {
"name": "checkpoints",
"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": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"checkpoint_volume_id": {
"name": "checkpoint_volume_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"model_name": {
"name": "model_name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"civitai_id": {
"name": "civitai_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"civitai_version_id": {
"name": "civitai_version_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"civitai_url": {
"name": "civitai_url",
"type": "text",
"primaryKey": false,
"notNull": false
},
"civitai_download_url": {
"name": "civitai_download_url",
"type": "text",
"primaryKey": false,
"notNull": false
},
"civitai_model_response": {
"name": "civitai_model_response",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"hf_url": {
"name": "hf_url",
"type": "text",
"primaryKey": false,
"notNull": false
},
"s3_url": {
"name": "s3_url",
"type": "text",
"primaryKey": false,
"notNull": false
},
"client_url": {
"name": "client_url",
"type": "text",
"primaryKey": false,
"notNull": false
},
"is_public": {
"name": "is_public",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"status": {
"name": "status",
"type": "resource_upload",
"primaryKey": false,
"notNull": true,
"default": "'started'"
},
"upload_machine_id": {
"name": "upload_machine_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"upload_type": {
"name": "upload_type",
"type": "model_upload_type",
"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": {
"checkpoints_user_id_users_id_fk": {
"name": "checkpoints_user_id_users_id_fk",
"tableFrom": "checkpoints",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"checkpoints_checkpoint_volume_id_workflow_runs_id_fk": {
"name": "checkpoints_checkpoint_volume_id_workflow_runs_id_fk",
"tableFrom": "checkpoints",
"tableTo": "workflow_runs",
"columnsFrom": [
"checkpoint_volume_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"checkpoint_volume": {
"name": "checkpoint_volume",
"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": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"volume_name": {
"name": "volume_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()"
},
"disabled": {
"name": "disabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
}
},
"indexes": {},
"foreignKeys": {
"checkpoint_volume_user_id_users_id_fk": {
"name": "checkpoint_volume_user_id_users_id_fk",
"tableFrom": "checkpoint_volume",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"deployments": { "deployments": {
"name": "deployments", "name": "deployments",
"schema": "comfyui_deploy", "schema": "comfyui_deploy",
@@ -506,12 +738,6 @@
"primaryKey": false, "primaryKey": false,
"notNull": true, "notNull": true,
"default": "now()" "default": "now()"
},
"started_at": {
"name": "started_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
} }
}, },
"indexes": {}, "indexes": {},
@@ -732,6 +958,22 @@
"comfy-deploy-serverless": "comfy-deploy-serverless" "comfy-deploy-serverless": "comfy-deploy-serverless"
} }
}, },
"model_upload_type": {
"name": "model_upload_type",
"values": {
"civitai": "civitai",
"huggingface": "huggingface",
"other": "other"
}
},
"resource_upload": {
"name": "resource_upload",
"values": {
"started": "started",
"failed": "failed",
"succeded": "succeded"
}
},
"workflow_run_origin": { "workflow_run_origin": {
"name": "workflow_run_origin", "name": "workflow_run_origin",
"values": { "values": {
+257 -23
View File
@@ -1,6 +1,6 @@
{ {
"id": "1425ee00-66fb-4541-8da7-19b217944545", "id": "fed3e81d-c0d7-4deb-a63a-370039fb5edc",
"prevId": "1ca4fdb7-c0c4-4c39-8b47-f40282293da0", "prevId": "4d5b29d0-848f-4c2e-a2cd-2932f1fa38c6",
"version": "5", "version": "5",
"dialect": "pg", "dialect": "pg",
"tables": { "tables": {
@@ -88,6 +88,244 @@
} }
} }
}, },
"checkpoints": {
"name": "checkpoints",
"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": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"checkpoint_volume_id": {
"name": "checkpoint_volume_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"model_name": {
"name": "model_name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"civitai_id": {
"name": "civitai_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"civitai_version_id": {
"name": "civitai_version_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"civitai_url": {
"name": "civitai_url",
"type": "text",
"primaryKey": false,
"notNull": false
},
"civitai_download_url": {
"name": "civitai_download_url",
"type": "text",
"primaryKey": false,
"notNull": false
},
"civitai_model_response": {
"name": "civitai_model_response",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"hf_url": {
"name": "hf_url",
"type": "text",
"primaryKey": false,
"notNull": false
},
"s3_url": {
"name": "s3_url",
"type": "text",
"primaryKey": false,
"notNull": false
},
"client_url": {
"name": "client_url",
"type": "text",
"primaryKey": false,
"notNull": false
},
"is_public": {
"name": "is_public",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"status": {
"name": "status",
"type": "resource_upload",
"primaryKey": false,
"notNull": true,
"default": "'started'"
},
"upload_machine_id": {
"name": "upload_machine_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"upload_type": {
"name": "upload_type",
"type": "model_upload_type",
"primaryKey": false,
"notNull": true
},
"build_log": {
"name": "build_log",
"type": "text",
"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": {
"checkpoints_user_id_users_id_fk": {
"name": "checkpoints_user_id_users_id_fk",
"tableFrom": "checkpoints",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"checkpoints_checkpoint_volume_id_workflow_runs_id_fk": {
"name": "checkpoints_checkpoint_volume_id_workflow_runs_id_fk",
"tableFrom": "checkpoints",
"tableTo": "workflow_runs",
"columnsFrom": [
"checkpoint_volume_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"checkpoint_volume": {
"name": "checkpoint_volume",
"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": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"volume_name": {
"name": "volume_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()"
},
"disabled": {
"name": "disabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
}
},
"indexes": {},
"foreignKeys": {
"checkpoint_volume_user_id_users_id_fk": {
"name": "checkpoint_volume_user_id_users_id_fk",
"tableFrom": "checkpoint_volume",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"deployments": { "deployments": {
"name": "deployments", "name": "deployments",
"schema": "comfyui_deploy", "schema": "comfyui_deploy",
@@ -129,12 +367,6 @@
"primaryKey": false, "primaryKey": false,
"notNull": true "notNull": true
}, },
"share_slug": {
"name": "share_slug",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": { "description": {
"name": "description", "name": "description",
"type": "text", "type": "text",
@@ -224,15 +456,7 @@
} }
}, },
"compositePrimaryKeys": {}, "compositePrimaryKeys": {},
"uniqueConstraints": { "uniqueConstraints": {}
"deployments_share_slug_unique": {
"name": "deployments_share_slug_unique",
"nullsNotDistinct": false,
"columns": [
"share_slug"
]
}
}
}, },
"machines": { "machines": {
"name": "machines", "name": "machines",
@@ -520,12 +744,6 @@
"primaryKey": false, "primaryKey": false,
"notNull": true, "notNull": true,
"default": "now()" "default": "now()"
},
"started_at": {
"name": "started_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
} }
}, },
"indexes": {}, "indexes": {},
@@ -746,6 +964,22 @@
"comfy-deploy-serverless": "comfy-deploy-serverless" "comfy-deploy-serverless": "comfy-deploy-serverless"
} }
}, },
"model_upload_type": {
"name": "model_upload_type",
"values": {
"civitai": "civitai",
"huggingface": "huggingface",
"other": "other"
}
},
"resource_upload": {
"name": "resource_upload",
"values": {
"started": "started",
"error": "error",
"succeded": "succeded"
}
},
"workflow_run_origin": { "workflow_run_origin": {
"name": "workflow_run_origin", "name": "workflow_run_origin",
"values": { "values": {
-824
View File
@@ -1,824 +0,0 @@
{
"id": "97662b25-3992-4859-9bdc-560e2a70daea",
"prevId": "1425ee00-66fb-4541-8da7-19b217944545",
"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"
]
}
}
},
"auth_requests": {
"name": "auth_requests",
"schema": "comfyui_deploy",
"columns": {
"request_id": {
"name": "request_id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"api_hash": {
"name": "api_hash",
"type": "text",
"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": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"deployments": {
"name": "deployments",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"workflow_version_id": {
"name": "workflow_version_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"machine_id": {
"name": "machine_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"share_slug": {
"name": "share_slug",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"showcase_media": {
"name": "showcase_media",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"environment": {
"name": "environment",
"type": "deployment_environment",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"deployments_user_id_users_id_fk": {
"name": "deployments_user_id_users_id_fk",
"tableFrom": "deployments",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_workflow_version_id_workflow_versions_id_fk": {
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "deployments",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"deployments_workflow_id_workflows_id_fk": {
"name": "deployments_workflow_id_workflows_id_fk",
"tableFrom": "deployments",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_machine_id_machines_id_fk": {
"name": "deployments_machine_id_machines_id_fk",
"tableFrom": "deployments",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"deployments_share_slug_unique": {
"name": "deployments_share_slug_unique",
"nullsNotDistinct": false,
"columns": [
"share_slug"
]
}
}
},
"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()"
},
"started_at": {
"name": "started_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
},
"workflow_runs_workflow_id_workflows_id_fk": {
"name": "workflow_runs_workflow_id_workflows_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"workflow_runs_machine_id_machines_id_fk": {
"name": "workflow_runs_machine_id_machines_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflows": {
"name": "workflows",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflows_user_id_users_id_fk": {
"name": "workflows_user_id_users_id_fk",
"tableFrom": "workflows",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_versions": {
"name": "workflow_versions",
"schema": "comfyui_deploy",
"columns": {
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"workflow": {
"name": "workflow",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"workflow_api": {
"name": "workflow_api",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"snapshot": {
"name": "snapshot",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflow_versions_workflow_id_workflows_id_fk": {
"name": "workflow_versions_workflow_id_workflows_id_fk",
"tableFrom": "workflow_versions",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {
"deployment_environment": {
"name": "deployment_environment",
"values": {
"staging": "staging",
"production": "production",
"public-share": "public-share"
}
},
"machine_gpu": {
"name": "machine_gpu",
"values": {
"T4": "T4",
"A10G": "A10G",
"A100": "A100"
}
},
"machine_status": {
"name": "machine_status",
"values": {
"ready": "ready",
"building": "building",
"error": "error"
}
},
"machine_type": {
"name": "machine_type",
"values": {
"classic": "classic",
"runpod-serverless": "runpod-serverless",
"modal-serverless": "modal-serverless",
"comfy-deploy-serverless": "comfy-deploy-serverless"
}
},
"workflow_run_origin": {
"name": "workflow_run_origin",
"values": {
"manual": "manual",
"api": "api",
"public-share": "public-share"
}
},
"workflow_run_status": {
"name": "workflow_run_status",
"values": {
"not-started": "not-started",
"running": "running",
"uploading": "uploading",
"success": "success",
"failed": "failed"
}
}
},
"schemas": {
"comfyui_deploy": "comfyui_deploy"
},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
}
}
-830
View File
@@ -1,830 +0,0 @@
{
"id": "8d654f92-7f7e-420f-bbd3-73b6b27adf35",
"prevId": "97662b25-3992-4859-9bdc-560e2a70daea",
"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"
]
}
}
},
"auth_requests": {
"name": "auth_requests",
"schema": "comfyui_deploy",
"columns": {
"request_id": {
"name": "request_id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"api_hash": {
"name": "api_hash",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"expired_date": {
"name": "expired_date",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"deployments": {
"name": "deployments",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"workflow_version_id": {
"name": "workflow_version_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"machine_id": {
"name": "machine_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"share_slug": {
"name": "share_slug",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"showcase_media": {
"name": "showcase_media",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"environment": {
"name": "environment",
"type": "deployment_environment",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"deployments_user_id_users_id_fk": {
"name": "deployments_user_id_users_id_fk",
"tableFrom": "deployments",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_workflow_version_id_workflow_versions_id_fk": {
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "deployments",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"deployments_workflow_id_workflows_id_fk": {
"name": "deployments_workflow_id_workflows_id_fk",
"tableFrom": "deployments",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_machine_id_machines_id_fk": {
"name": "deployments_machine_id_machines_id_fk",
"tableFrom": "deployments",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"deployments_share_slug_unique": {
"name": "deployments_share_slug_unique",
"nullsNotDistinct": false,
"columns": [
"share_slug"
]
}
}
},
"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()"
},
"started_at": {
"name": "started_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
},
"workflow_runs_workflow_id_workflows_id_fk": {
"name": "workflow_runs_workflow_id_workflows_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"workflow_runs_machine_id_machines_id_fk": {
"name": "workflow_runs_machine_id_machines_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflows": {
"name": "workflows",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflows_user_id_users_id_fk": {
"name": "workflows_user_id_users_id_fk",
"tableFrom": "workflows",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_versions": {
"name": "workflow_versions",
"schema": "comfyui_deploy",
"columns": {
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"workflow": {
"name": "workflow",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"workflow_api": {
"name": "workflow_api",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"snapshot": {
"name": "snapshot",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflow_versions_workflow_id_workflows_id_fk": {
"name": "workflow_versions_workflow_id_workflows_id_fk",
"tableFrom": "workflow_versions",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {
"deployment_environment": {
"name": "deployment_environment",
"values": {
"staging": "staging",
"production": "production",
"public-share": "public-share"
}
},
"machine_gpu": {
"name": "machine_gpu",
"values": {
"T4": "T4",
"A10G": "A10G",
"A100": "A100"
}
},
"machine_status": {
"name": "machine_status",
"values": {
"ready": "ready",
"building": "building",
"error": "error"
}
},
"machine_type": {
"name": "machine_type",
"values": {
"classic": "classic",
"runpod-serverless": "runpod-serverless",
"modal-serverless": "modal-serverless",
"comfy-deploy-serverless": "comfy-deploy-serverless"
}
},
"workflow_run_origin": {
"name": "workflow_run_origin",
"values": {
"manual": "manual",
"api": "api",
"public-share": "public-share"
}
},
"workflow_run_status": {
"name": "workflow_run_status",
"values": {
"not-started": "not-started",
"running": "running",
"uploading": "uploading",
"success": "success",
"failed": "failed"
}
}
},
"schemas": {
"comfyui_deploy": "comfyui_deploy"
},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
}
}
-894
View File
@@ -1,894 +0,0 @@
{
"id": "2b2a5d0a-2494-45ea-9d4a-58a70df97829",
"prevId": "8d654f92-7f7e-420f-bbd3-73b6b27adf35",
"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"
]
}
}
},
"auth_requests": {
"name": "auth_requests",
"schema": "comfyui_deploy",
"columns": {
"request_id": {
"name": "request_id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"api_hash": {
"name": "api_hash",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"expired_date": {
"name": "expired_date",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"deployments": {
"name": "deployments",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"workflow_version_id": {
"name": "workflow_version_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"machine_id": {
"name": "machine_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"share_slug": {
"name": "share_slug",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"showcase_media": {
"name": "showcase_media",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"environment": {
"name": "environment",
"type": "deployment_environment",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"deployments_user_id_users_id_fk": {
"name": "deployments_user_id_users_id_fk",
"tableFrom": "deployments",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_workflow_version_id_workflow_versions_id_fk": {
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "deployments",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"deployments_workflow_id_workflows_id_fk": {
"name": "deployments_workflow_id_workflows_id_fk",
"tableFrom": "deployments",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_machine_id_machines_id_fk": {
"name": "deployments_machine_id_machines_id_fk",
"tableFrom": "deployments",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"deployments_share_slug_unique": {
"name": "deployments_share_slug_unique",
"nullsNotDistinct": false,
"columns": [
"share_slug"
]
}
}
},
"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": {}
},
"user_usage": {
"name": "user_usage",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"usage_time": {
"name": "usage_time",
"type": "real",
"primaryKey": false,
"notNull": true,
"default": 0
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"ended_at": {
"name": "ended_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"user_usage_user_id_users_id_fk": {
"name": "user_usage_user_id_users_id_fk",
"tableFrom": "user_usage",
"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()"
},
"started_at": {
"name": "started_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
},
"workflow_runs_workflow_id_workflows_id_fk": {
"name": "workflow_runs_workflow_id_workflows_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"workflow_runs_machine_id_machines_id_fk": {
"name": "workflow_runs_machine_id_machines_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflows": {
"name": "workflows",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflows_user_id_users_id_fk": {
"name": "workflows_user_id_users_id_fk",
"tableFrom": "workflows",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_versions": {
"name": "workflow_versions",
"schema": "comfyui_deploy",
"columns": {
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"workflow": {
"name": "workflow",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"workflow_api": {
"name": "workflow_api",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"snapshot": {
"name": "snapshot",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflow_versions_workflow_id_workflows_id_fk": {
"name": "workflow_versions_workflow_id_workflows_id_fk",
"tableFrom": "workflow_versions",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {
"deployment_environment": {
"name": "deployment_environment",
"values": {
"staging": "staging",
"production": "production",
"public-share": "public-share"
}
},
"machine_gpu": {
"name": "machine_gpu",
"values": {
"T4": "T4",
"A10G": "A10G",
"A100": "A100"
}
},
"machine_status": {
"name": "machine_status",
"values": {
"ready": "ready",
"building": "building",
"error": "error"
}
},
"machine_type": {
"name": "machine_type",
"values": {
"classic": "classic",
"runpod-serverless": "runpod-serverless",
"modal-serverless": "modal-serverless",
"comfy-deploy-serverless": "comfy-deploy-serverless"
}
},
"workflow_run_origin": {
"name": "workflow_run_origin",
"values": {
"manual": "manual",
"api": "api",
"public-share": "public-share"
}
},
"workflow_run_status": {
"name": "workflow_run_status",
"values": {
"not-started": "not-started",
"running": "running",
"uploading": "uploading",
"success": "success",
"failed": "failed"
}
}
},
"schemas": {
"comfyui_deploy": "comfyui_deploy"
},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
}
}
-970
View File
@@ -1,970 +0,0 @@
{
"id": "4db08fc3-2444-42da-b742-f1832ad8caf1",
"prevId": "2b2a5d0a-2494-45ea-9d4a-58a70df97829",
"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"
]
}
}
},
"auth_requests": {
"name": "auth_requests",
"schema": "comfyui_deploy",
"columns": {
"request_id": {
"name": "request_id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"api_hash": {
"name": "api_hash",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"expired_date": {
"name": "expired_date",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"deployments": {
"name": "deployments",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"workflow_version_id": {
"name": "workflow_version_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"machine_id": {
"name": "machine_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"share_slug": {
"name": "share_slug",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"showcase_media": {
"name": "showcase_media",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"environment": {
"name": "environment",
"type": "deployment_environment",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"deployments_user_id_users_id_fk": {
"name": "deployments_user_id_users_id_fk",
"tableFrom": "deployments",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_workflow_version_id_workflow_versions_id_fk": {
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "deployments",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"deployments_workflow_id_workflows_id_fk": {
"name": "deployments_workflow_id_workflows_id_fk",
"tableFrom": "deployments",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_machine_id_machines_id_fk": {
"name": "deployments_machine_id_machines_id_fk",
"tableFrom": "deployments",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"deployments_share_slug_unique": {
"name": "deployments_share_slug_unique",
"nullsNotDistinct": false,
"columns": [
"share_slug"
]
}
}
},
"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": {}
},
"subscription_status": {
"name": "subscription_status",
"schema": "comfyui_deploy",
"columns": {
"stripe_customer_id": {
"name": "stripe_customer_id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"plan": {
"name": "plan",
"type": "subscription_plan",
"primaryKey": false,
"notNull": true
},
"status": {
"name": "status",
"type": "subscription_plan_status",
"primaryKey": false,
"notNull": true
},
"subscription_plan_id": {
"name": "subscription_plan_id",
"type": "text",
"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": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"user_usage": {
"name": "user_usage",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"usage_time": {
"name": "usage_time",
"type": "real",
"primaryKey": false,
"notNull": true,
"default": 0
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"ended_at": {
"name": "ended_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"user_usage_user_id_users_id_fk": {
"name": "user_usage_user_id_users_id_fk",
"tableFrom": "user_usage",
"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()"
},
"started_at": {
"name": "started_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"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"
}
},
"subscription_plan": {
"name": "subscription_plan",
"values": {
"basic": "basic",
"pro": "pro",
"enterprise": "enterprise"
}
},
"subscription_plan_status": {
"name": "subscription_plan_status",
"values": {
"active": "active",
"deleted": "deleted",
"paused": "paused"
}
},
"workflow_run_origin": {
"name": "workflow_run_origin",
"values": {
"manual": "manual",
"api": "api",
"public-share": "public-share"
}
},
"workflow_run_status": {
"name": "workflow_run_status",
"values": {
"not-started": "not-started",
"running": "running",
"uploading": "uploading",
"success": "success",
"failed": "failed"
}
}
},
"schemas": {
"comfyui_deploy": "comfyui_deploy"
},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
}
}
-984
View File
@@ -1,984 +0,0 @@
{
"id": "cde8f758-0055-4326-981d-293ac84db54a",
"prevId": "4db08fc3-2444-42da-b742-f1832ad8caf1",
"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"
]
}
}
},
"auth_requests": {
"name": "auth_requests",
"schema": "comfyui_deploy",
"columns": {
"request_id": {
"name": "request_id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"api_hash": {
"name": "api_hash",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"expired_date": {
"name": "expired_date",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"deployments": {
"name": "deployments",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"workflow_version_id": {
"name": "workflow_version_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"machine_id": {
"name": "machine_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"share_slug": {
"name": "share_slug",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"showcase_media": {
"name": "showcase_media",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"environment": {
"name": "environment",
"type": "deployment_environment",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"deployments_user_id_users_id_fk": {
"name": "deployments_user_id_users_id_fk",
"tableFrom": "deployments",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_workflow_version_id_workflow_versions_id_fk": {
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "deployments",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"deployments_workflow_id_workflows_id_fk": {
"name": "deployments_workflow_id_workflows_id_fk",
"tableFrom": "deployments",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_machine_id_machines_id_fk": {
"name": "deployments_machine_id_machines_id_fk",
"tableFrom": "deployments",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"deployments_share_slug_unique": {
"name": "deployments_share_slug_unique",
"nullsNotDistinct": false,
"columns": [
"share_slug"
]
}
}
},
"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": {}
},
"subscription_status": {
"name": "subscription_status",
"schema": "comfyui_deploy",
"columns": {
"stripe_customer_id": {
"name": "stripe_customer_id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"plan": {
"name": "plan",
"type": "subscription_plan",
"primaryKey": false,
"notNull": true
},
"status": {
"name": "status",
"type": "subscription_plan_status",
"primaryKey": false,
"notNull": true
},
"subscription_id": {
"name": "subscription_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"subscription_item_plan_id": {
"name": "subscription_item_plan_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"subscription_item_api_id": {
"name": "subscription_item_api_id",
"type": "text",
"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": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"user_usage": {
"name": "user_usage",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"usage_time": {
"name": "usage_time",
"type": "real",
"primaryKey": false,
"notNull": true,
"default": 0
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"ended_at": {
"name": "ended_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"user_usage_user_id_users_id_fk": {
"name": "user_usage_user_id_users_id_fk",
"tableFrom": "user_usage",
"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()"
},
"started_at": {
"name": "started_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"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"
}
},
"subscription_plan": {
"name": "subscription_plan",
"values": {
"basic": "basic",
"pro": "pro",
"enterprise": "enterprise"
}
},
"subscription_plan_status": {
"name": "subscription_plan_status",
"values": {
"active": "active",
"deleted": "deleted",
"paused": "paused"
}
},
"workflow_run_origin": {
"name": "workflow_run_origin",
"values": {
"manual": "manual",
"api": "api",
"public-share": "public-share"
}
},
"workflow_run_status": {
"name": "workflow_run_status",
"values": {
"not-started": "not-started",
"running": "running",
"uploading": "uploading",
"success": "success",
"failed": "failed"
}
}
},
"schemas": {
"comfyui_deploy": "comfyui_deploy"
},
"_meta": {
"schemas": {},
"tables": {},
"columns": {
"\"comfyui_deploy\".\"subscription_status\".\"subscription_plan_id\"": "\"comfyui_deploy\".\"subscription_status\".\"subscription_id\""
}
}
}
-989
View File
@@ -1,989 +0,0 @@
{
"id": "bd893271-b9ea-4832-a3e8-a6970b9f20d9",
"prevId": "cde8f758-0055-4326-981d-293ac84db54a",
"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"
]
}
}
},
"auth_requests": {
"name": "auth_requests",
"schema": "comfyui_deploy",
"columns": {
"request_id": {
"name": "request_id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"api_hash": {
"name": "api_hash",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"expired_date": {
"name": "expired_date",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"deployments": {
"name": "deployments",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"workflow_version_id": {
"name": "workflow_version_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"machine_id": {
"name": "machine_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"share_slug": {
"name": "share_slug",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"showcase_media": {
"name": "showcase_media",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"environment": {
"name": "environment",
"type": "deployment_environment",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"deployments_user_id_users_id_fk": {
"name": "deployments_user_id_users_id_fk",
"tableFrom": "deployments",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_workflow_version_id_workflow_versions_id_fk": {
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "deployments",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"deployments_workflow_id_workflows_id_fk": {
"name": "deployments_workflow_id_workflows_id_fk",
"tableFrom": "deployments",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_machine_id_machines_id_fk": {
"name": "deployments_machine_id_machines_id_fk",
"tableFrom": "deployments",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"deployments_share_slug_unique": {
"name": "deployments_share_slug_unique",
"nullsNotDistinct": false,
"columns": [
"share_slug"
]
}
}
},
"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": {}
},
"subscription_status": {
"name": "subscription_status",
"schema": "comfyui_deploy",
"columns": {
"stripe_customer_id": {
"name": "stripe_customer_id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"plan": {
"name": "plan",
"type": "subscription_plan",
"primaryKey": false,
"notNull": true
},
"status": {
"name": "status",
"type": "subscription_plan_status",
"primaryKey": false,
"notNull": true
},
"subscription_id": {
"name": "subscription_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"subscription_item_plan_id": {
"name": "subscription_item_plan_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"subscription_item_api_id": {
"name": "subscription_item_api_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"cancel_at_period_end": {
"name": "cancel_at_period_end",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"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": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"user_usage": {
"name": "user_usage",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"usage_time": {
"name": "usage_time",
"type": "real",
"primaryKey": false,
"notNull": true,
"default": 0
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"ended_at": {
"name": "ended_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"user_usage_user_id_users_id_fk": {
"name": "user_usage_user_id_users_id_fk",
"tableFrom": "user_usage",
"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()"
},
"started_at": {
"name": "started_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"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"
}
},
"subscription_plan": {
"name": "subscription_plan",
"values": {
"basic": "basic",
"pro": "pro",
"enterprise": "enterprise"
}
},
"subscription_plan_status": {
"name": "subscription_plan_status",
"values": {
"active": "active",
"deleted": "deleted",
"paused": "paused"
}
},
"workflow_run_origin": {
"name": "workflow_run_origin",
"values": {
"manual": "manual",
"api": "api",
"public-share": "public-share"
}
},
"workflow_run_status": {
"name": "workflow_run_status",
"values": {
"not-started": "not-started",
"running": "running",
"uploading": "uploading",
"success": "success",
"failed": "failed"
}
}
},
"schemas": {
"comfyui_deploy": "comfyui_deploy"
},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+4 -95
View File
@@ -222,106 +222,15 @@
{ {
"idx": 31, "idx": 31,
"version": "5", "version": "5",
"when": 1705763980972, "when": 1705975916818,
"tag": "0031_fast_lyja", "tag": "0031_safe_multiple_man",
"breakpoints": true "breakpoints": true
}, },
{ {
"idx": 32, "idx": 32,
"version": "5", "version": "5",
"when": 1705806921697, "when": 1705979098372,
"tag": "0032_shallow_vermin", "tag": "0032_material_wallflower",
"breakpoints": true
},
{
"idx": 33,
"version": "5",
"when": 1705853314500,
"tag": "0033_awesome_human_fly",
"breakpoints": true
},
{
"idx": 34,
"version": "5",
"when": 1705902960991,
"tag": "0034_even_lady_ursula",
"breakpoints": true
},
{
"idx": 35,
"version": "5",
"when": 1705981452482,
"tag": "0035_fearless_golden_guardian",
"breakpoints": true
},
{
"idx": 36,
"version": "5",
"when": 1706081335387,
"tag": "0036_flippant_meltdown",
"breakpoints": true
},
{
"idx": 37,
"version": "5",
"when": 1706086271525,
"tag": "0037_eager_cyclops",
"breakpoints": true
},
{
"idx": 38,
"version": "5",
"when": 1706095853896,
"tag": "0038_yummy_darkhawk",
"breakpoints": true
},
{
"idx": 39,
"version": "5",
"when": 1706109812261,
"tag": "0039_nostalgic_lyja",
"breakpoints": true
},
{
"idx": 40,
"version": "5",
"when": 1706110859352,
"tag": "0040_salty_archangel",
"breakpoints": true
},
{
"idx": 41,
"version": "5",
"when": 1706111421524,
"tag": "0041_thick_norrin_radd",
"breakpoints": true
},
{
"idx": 42,
"version": "5",
"when": 1706164614659,
"tag": "0042_windy_madelyne_pryor",
"breakpoints": true
},
{
"idx": 43,
"version": "5",
"when": 1706241449348,
"tag": "0043_wealthy_nicolaos",
"breakpoints": true
},
{
"idx": 44,
"version": "5",
"when": 1706317908300,
"tag": "0044_panoramic_mister_fear",
"breakpoints": true
},
{
"idx": 45,
"version": "5",
"when": 1706336448134,
"tag": "0045_careful_cerise",
"breakpoints": true "breakpoints": true
} }
] ]
+7 -12
View File
@@ -12,31 +12,26 @@ let sslMode: string | boolean = process.env.SSL || "require";
if (sslMode === "false") sslMode = false; if (sslMode === "false") sslMode = false;
let connectionString = process.env.POSTGRES_URL!; console.log(migrationsFolderName, sslMode);
const isDevContainer = process.env.REMOTE_CONTAINERS !== undefined;
if (isDevContainer)
connectionString = connectionString.replace(
"localhost",
"host.docker.internal",
);
const connectionString = process.env.POSTGRES_URL!;
console.log(connectionString);
const sql = postgres(connectionString, { max: 1, ssl: sslMode as any }); const sql = postgres(connectionString, { max: 1, ssl: sslMode as any });
const db = drizzle(sql, { const db = drizzle(sql, {
logger: true, logger: true,
}); });
let retries = 5; let retries = 5;
while (retries) { while(retries) {
try { try {
await sql`SELECT NOW()`; await sql`SELECT NOW()`;
console.log("Database is live"); console.log('Database is live');
break; break;
} catch (error) { } catch (error) {
console.error("Database is not live yet", error); console.error('Database is not live yet', error);
retries -= 1; retries -= 1;
console.log(`Retries left: ${retries}`); console.log(`Retries left: ${retries}`);
await new Promise((res) => setTimeout(res, 1000)); await new Promise(res => setTimeout(res, 1000));
} }
} }
+12 -10
View File
@@ -12,33 +12,29 @@
"migrate-production": "bun run migrate.mts", "migrate-production": "bun run migrate.mts",
"migrate-local": "SSL=false LOCAL=true bun run migrate.mts", "migrate-local": "SSL=false LOCAL=true bun run migrate.mts",
"db-up": "docker-compose up", "db-up": "docker-compose up",
"db-dev": "bun run db-up && bun run migrate-local", "db-dev": "bun run db-up && bun run migrate-local"
"lint:fix": "bunx @biomejs/biome lint --apply ./src"
}, },
"dependencies": { "dependencies": {
"@algolia/autocomplete-core": "^1.13.0", "@algolia/autocomplete-core": "^1.13.0",
"@aws-sdk/client-s3": "^3.472.0", "@aws-sdk/client-s3": "^3.472.0",
"@aws-sdk/s3-request-presigner": "^3.472.0", "@aws-sdk/s3-request-presigner": "^3.472.0",
"@clerk/nextjs": "4.29.5", "@clerk/nextjs": "^4.29.3",
"@headlessui/react": "^1.7.17", "@headlessui/react": "^1.7.17",
"@headlessui/tailwindcss": "^0.2.0", "@headlessui/tailwindcss": "^0.2.0",
"@hono/swagger-ui": "^0.2.1", "@hono/swagger-ui": "^0.2.1",
"@hono/zod-openapi": "^0.9.5", "@hono/zod-openapi": "^0.9.5",
"@hono/zod-validator": "^0.1.11", "@hono/zod-validator": "^0.1.11",
"@hookform/resolvers": "^3.3.2", "@hookform/resolvers": "^3.3.2",
"@lemonsqueezy/lemonsqueezy.js": "^1.2.5",
"@mdx-js/loader": "^3.0.0", "@mdx-js/loader": "^3.0.0",
"@mdx-js/react": "^3.0.0", "@mdx-js/react": "^3.0.0",
"@neondatabase/serverless": "^0.6.0", "@neondatabase/serverless": "^0.6.0",
"@next/mdx": "^14.0.4", "@next/mdx": "^14.0.4",
"@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2", "@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-progress": "^1.0.3",
"@radix-ui/react-radio-group": "^1.1.3", "@radix-ui/react-radio-group": "^1.1.3",
"@radix-ui/react-scroll-area": "^1.0.5", "@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-select": "^2.0.0", "@radix-ui/react-select": "^2.0.0",
@@ -49,7 +45,6 @@
"@radix-ui/react-toggle": "^1.0.3", "@radix-ui/react-toggle": "^1.0.3",
"@radix-ui/react-tooltip": "^1.0.7", "@radix-ui/react-tooltip": "^1.0.7",
"@sindresorhus/slugify": "^2.2.1", "@sindresorhus/slugify": "^2.2.1",
"@stripe/stripe-js": "^2.4.0",
"@tailwindcss/typography": "^0.5.10", "@tailwindcss/typography": "^0.5.10",
"@tanstack/react-table": "^8.10.7", "@tanstack/react-table": "^8.10.7",
"@tanstack/react-virtual": "beta", "@tanstack/react-virtual": "beta",
@@ -76,7 +71,6 @@
"mdx-annotations": "^0.1.4", "mdx-annotations": "^0.1.4",
"million": "latest", "million": "latest",
"mitata": "^0.1.6", "mitata": "^0.1.6",
"ms": "^2.1.3",
"nanoid": "^5.0.4", "nanoid": "^5.0.4",
"next": "14.1", "next": "14.1",
"next-plausible": "^3.12.0", "next-plausible": "^3.12.0",
@@ -98,7 +92,6 @@
"shikiji": "^0.9.3", "shikiji": "^0.9.3",
"simple-functional-loader": "^1.2.1", "simple-functional-loader": "^1.2.1",
"sonner": "^1.2.4", "sonner": "^1.2.4",
"stripe": "^14.13.0",
"swagger-ui-react": "^5.11.0", "swagger-ui-react": "^5.11.0",
"swr": "^2.2.4", "swr": "^2.2.4",
"tailwind-merge": "^2.1.0", "tailwind-merge": "^2.1.0",
@@ -112,17 +105,26 @@
"zustand": "^4.4.7" "zustand": "^4.4.7"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "1.5.2", "@trivago/prettier-plugin-sort-imports": "4.1.1",
"@types/node": "^20", "@types/node": "^20",
"@types/react": "^18", "@types/react": "^18",
"@types/react-dom": "^18", "@types/react-dom": "^18",
"@typescript-eslint/eslint-plugin": "^6.13.2",
"@typescript-eslint/parser": "^6.13.2",
"autoprefixer": "^10.0.1", "autoprefixer": "^10.0.1",
"concurrently": "^8.2.2", "concurrently": "^8.2.2",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"drizzle-kit": "^0.20.6", "drizzle-kit": "^0.20.6",
"eslint": "8.34.0", "eslint": "8.34.0",
"eslint-config-next": "^14.0.4",
"eslint-config-prettier": "^8.6.0",
"eslint-config-turbo": "latest",
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-unused-imports": "^3.0.0",
"postcss": "^8", "postcss": "^8",
"postgres": "^3.4.3", "postgres": "^3.4.3",
"prettier": "2.8.6",
"prettier-plugin-tailwindcss": "0.2.5",
"sharp": "^0.33.1", "sharp": "^0.33.1",
"tailwindcss": "^3.3.0", "tailwindcss": "^3.3.0",
"typescript": "^5" "typescript": "^5"
+11 -42
View File
@@ -1,3 +1,4 @@
import { app } from "../../../../routes/app";
import { registerCreateRunRoute } from "@/routes/registerCreateRunRoute"; import { registerCreateRunRoute } from "@/routes/registerCreateRunRoute";
import { registerGetOutputRoute } from "@/routes/registerGetOutputRoute"; import { registerGetOutputRoute } from "@/routes/registerGetOutputRoute";
import { registerUploadRoute } from "@/routes/registerUploadRoute"; import { registerUploadRoute } from "@/routes/registerUploadRoute";
@@ -5,11 +6,7 @@ import { isKeyRevoked } from "@/server/curdApiKeys";
import { parseJWT } from "@/server/parseJWT"; import { parseJWT } from "@/server/parseJWT";
import type { Context, Next } from "hono"; import type { Context, Next } from "hono";
import { handle } from "hono/vercel"; import { handle } from "hono/vercel";
import { app } from "../../../../routes/app";
import { registerWorkflowUploadRoute } from "@/routes/registerWorkflowUploadRoute";
import { registerGetAuthResponse } from "@/routes/registerGetAuthResponse";
import { registerGetWorkflowRoute } from "@/routes/registerGetWorkflow";
import { cors } from "hono/cors";
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
export const maxDuration = 300; // 5 minutes export const maxDuration = 300; // 5 minutes
@@ -19,24 +16,14 @@ declare module "hono" {
} }
} }
async function checkAuth(c: Context, next: Next, headers?: HeadersInit) { async function checkAuth(c: Context, next: Next) {
const token = c.req.raw.headers.get("Authorization")?.split(" ")?.[1]; // Assuming token is sent as "Bearer your_token" const token = c.req.raw.headers.get("Authorization")?.split(" ")?.[1]; // Assuming token is sent as "Bearer your_token"
const userData = token ? parseJWT(token) : undefined; const userData = token ? parseJWT(token) : undefined;
if (!userData || token === undefined) { if (!userData || token === undefined) {
return c.text("Invalid or expired token", { return c.text("Invalid or expired token", 401);
status: 401, } else {
headers: headers,
});
}
// If the key has expiration, this is a temporary key and not in our db, so we can skip checking
if (userData.exp === undefined) {
const revokedKey = await isKeyRevoked(token); const revokedKey = await isKeyRevoked(token);
if (revokedKey) if (revokedKey) return c.text("Revoked token", 401);
return c.text("Revoked token", {
status: 401,
headers: headers,
});
} }
c.set("apiKeyTokenData", userData); c.set("apiKeyTokenData", userData);
@@ -44,35 +31,18 @@ async function checkAuth(c: Context, next: Next, headers?: HeadersInit) {
await next(); await next();
} }
app.use("/run", checkAuth); app.use("/run", async (c, next) => {
app.use("/upload-url", checkAuth); return checkAuth(c, next);
const corsHandler = cors({
origin: "*",
allowHeaders: ["Authorization", "Content-Type"],
allowMethods: ["POST", "GET", "OPTIONS"],
exposeHeaders: ["Content-Length"],
maxAge: 600,
credentials: true,
}); });
// CORS Check app.use("/upload-url", async (c, next) => {
app.use("/workflow", corsHandler, checkAuth); return checkAuth(c, next);
app.use("/workflow-version/*", corsHandler, checkAuth); });
// create run endpoint
registerCreateRunRoute(app); registerCreateRunRoute(app);
registerGetOutputRoute(app); registerGetOutputRoute(app);
// file upload endpoint
registerUploadRoute(app); registerUploadRoute(app);
// Anon
registerGetAuthResponse(app);
registerWorkflowUploadRoute(app);
registerGetWorkflowRoute(app);
// The OpenAPI documentation will be available at /doc // The OpenAPI documentation will be available at /doc
app.doc("/doc", { app.doc("/doc", {
openapi: "3.0.0", openapi: "3.0.0",
@@ -99,4 +69,3 @@ const handler = handle(app);
export const GET = handler; export const GET = handler;
export const POST = handler; export const POST = handler;
export const OPTIONS = handler;
+3 -4
View File
@@ -1,12 +1,11 @@
import { parseDataSafe } from "../../../../lib/parseDataSafe";
import { handleResourceUpload } from "@/server/resource"; import { handleResourceUpload } from "@/server/resource";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { z } from "zod"; import { z } from "zod";
import { parseDataSafe } from "../../../../lib/parseDataSafe";
const Request = z.object({ const Request = z.object({
file_name: z.string(), file_name: z.string(),
run_id: z.string(), run_id: z.string(),
type: z.string(), type: z.string(),
}); });
@@ -30,7 +29,7 @@ export async function GET(request: Request) {
{ {
url: uploadUrl, url: uploadUrl,
}, },
{ status: 200 }, { status: 200 }
); );
} catch (error: unknown) { } catch (error: unknown) {
const errorMessage = const errorMessage =
@@ -39,7 +38,7 @@ export async function GET(request: Request) {
{ {
error: errorMessage, error: errorMessage,
}, },
{ status: 500 }, { status: 500 }
); );
} }
} }
@@ -1,175 +0,0 @@
import { auth, clerkClient } from "@clerk/nextjs";
import { headers } from "next/headers";
import { redirect } from "next/navigation";
import { stripe } from "../../../../../server/stripe";
import { NextResponse } from "next/server";
import { db } from "@/db/db";
import { subscriptionStatusTable } from "@/db/schema";
import { eq } from "drizzle-orm";
const secret = process.env.STRIPE_WEBHOOK_SECRET || "";
export async function POST(req: Request) {
try {
const body = await req.text();
const signature = headers().get("stripe-signature");
if (!signature)
return new NextResponse("Signature not found.", {
status: 500,
});
const event = stripe.webhooks.constructEvent(body, signature, secret);
console.log(event);
if (event.type === "checkout.session.completed") {
if (!event.data.object.customer_details?.email) {
throw new Error(`missing user email, ${event.id}`);
}
const userId = event.data.object.metadata?.userId;
const plan = event.data.object.metadata?.plan;
if (!userId) {
throw new Error(`missing itinerary_id on metadata, ${event.id}`);
}
if (!plan) {
throw new Error(`missing plan on metadata, ${event.id}`);
}
const orgId = event.data.object.metadata?.orgId;
const customerId =
typeof event.data.object.customer == "string"
? event.data.object.customer
: event.data.object.customer?.id;
const subscriptionId =
typeof event.data.object.subscription == "string"
? event.data.object.subscription
: event.data.object.subscription?.id;
if (!customerId) {
throw new Error(`missing customerId, ${event.id}`);
}
if (!subscriptionId) {
throw new Error(`missing subscriptionId, ${event.id}`);
}
const items = await stripe.subscriptionItems.list({
subscription: subscriptionId,
limit: 5,
});
// getting the subscription item id for the api plan
const subscription_item_api_id = items.data.find(
(x) => x.price.id === process.env.STRIPE_PR_API,
)?.id;
// the plan could be either pro or enterprise
const subscription_item_plan_id =
items.data.find((x) => x.price.id === process.env.STRIPE_PR_PRO)?.id ??
items.data.find((x) => x.price.id === process.env.STRIPE_PR_ENTERPRISE)
?.id;
if (!subscription_item_api_id) {
throw new Error(
`missing plan on subscription_item_api_id, ${event.id}`,
);
}
if (!subscription_item_plan_id) {
throw new Error(
`missing plan on subscription_item_plan_id, ${event.id}`,
);
}
console.log(items);
await db
.insert(subscriptionStatusTable)
.values({
stripe_customer_id: customerId,
org_id: orgId && orgId.length > 0 && orgId != "null" ? orgId : null,
user_id: userId,
subscription_id: subscriptionId,
plan: plan as "pro" | "enterprise" | "basic",
status: "active",
subscription_item_api_id: subscription_item_api_id,
subscription_item_plan_id: subscription_item_plan_id,
})
.onConflictDoNothing();
// updateDatabase(event.data.object.metadata.itinerary_id);
// sendEmail(event.data.object.customer_details.email);
} else if (event.type === "customer.subscription.paused") {
const customerId =
typeof event.data.object.customer == "string"
? event.data.object.customer
: event.data.object.customer?.id;
if (!customerId) {
throw new Error(`missing customerId, ${event.id}`);
}
await db
.update(subscriptionStatusTable)
.set({ status: "paused" })
.where(eq(subscriptionStatusTable.stripe_customer_id, customerId));
} else if (event.type === "customer.subscription.resumed") {
const customerId =
typeof event.data.object.customer == "string"
? event.data.object.customer
: event.data.object.customer?.id;
if (!customerId) {
throw new Error(`missing customerId, ${event.id}`);
}
await db
.update(subscriptionStatusTable)
.set({ status: "active" })
.where(eq(subscriptionStatusTable.stripe_customer_id, customerId));
} else if (event.type === "customer.subscription.deleted") {
const customerId =
typeof event.data.object.customer == "string"
? event.data.object.customer
: event.data.object.customer?.id;
if (!customerId) {
throw new Error(`missing customerId, ${event.id}`);
}
await db
.update(subscriptionStatusTable)
.set({ status: "deleted" })
.where(eq(subscriptionStatusTable.stripe_customer_id, customerId));
} else if (event.type === "customer.subscription.updated") {
const customerId =
typeof event.data.object.customer == "string"
? event.data.object.customer
: event.data.object.customer?.id;
if (!customerId) {
throw new Error(`missing customerId, ${event.id}`);
}
const cancel_at_period_end = event.data.object.cancel_at_period_end;
await db
.update(subscriptionStatusTable)
.set({ cancel_at_period_end: cancel_at_period_end })
.where(eq(subscriptionStatusTable.stripe_customer_id, customerId));
}
return NextResponse.json({ result: event, ok: true });
} catch (error) {
console.error(error);
return NextResponse.json(
{
message: `Something went wrong: ${error}`,
ok: false,
},
{ status: 500 },
);
}
}
@@ -1,45 +0,0 @@
import { stripe } from "@/server/stripe";
import { auth, clerkClient } from "@clerk/nextjs";
import { redirect } from "next/navigation";
import { getUrlServerSide } from "@/server/getUrlServerSide";
export async function GET(req: Request) {
const { userId, orgId } = auth();
const plan = new URL(req.url).searchParams.get("plan");
if (!userId) return redirect("/");
if (!plan) return redirect("/pricing");
const user = await clerkClient.users.getUser(userId);
const mapping = {
pro: process.env.STRIPE_PR_PRO,
enterprise: process.env.STRIPE_PR_ENTERPRISE,
};
const api = process.env.STRIPE_PR_API;
const session = await stripe.checkout.sessions.create({
success_url: getUrlServerSide(),
line_items: [
{
price: mapping[plan as "pro" | "enterprise"],
quantity: 1,
},
{
price: api,
},
],
metadata: {
userId: userId,
orgId: orgId ?? null,
plan: plan,
},
client_reference_id: orgId ?? userId,
customer_email: user.emailAddresses[0].emailAddress,
mode: "subscription",
});
if (session.url) redirect(session.url);
}
@@ -1,37 +0,0 @@
import { stripe } from "@/server/stripe";
import { auth } from "@clerk/nextjs";
import { redirect } from "next/navigation";
import { getUrlServerSide } from "@/server/getUrlServerSide";
import { getCurrentPlan } from "@/server/getCurrentPlan";
export async function GET(req: Request) {
const { userId, orgId } = auth();
if (!userId) return redirect("/");
const change = new URL(req.url).searchParams.get("change");
const sub = await getCurrentPlan({
org_id: orgId,
user_id: userId,
});
if (!sub) return redirect("/pricing");
const session = await stripe.billingPortal.sessions.create({
customer: sub.stripe_customer_id,
return_url: getUrlServerSide() + "/pricing",
// flow_data:
// change === "true" && sub.subscription_id
// ? {
// type: "subscription_update",
// subscription_update: {
// subscription: sub.subscription_id,
// },
// }
// : undefined,
});
redirect(session.url);
// if (session.url) redirect(session.url);
}
+39 -112
View File
@@ -1,129 +1,56 @@
import { parseDataSafe } from "../../../../lib/parseDataSafe"; import { parseDataSafe } from "../../../../lib/parseDataSafe";
import { db } from "@/db/db"; import { db } from "@/db/db";
import { import { workflowRunOutputs, workflowRunsTable } from "@/db/schema";
WorkflowRunStatusSchema,
userUsageTable,
workflowRunOutputs,
workflowRunsTable,
workflowTable,
} from "@/db/schema";
import { getCurrentPlan } from "@/server/getCurrentPlan";
import { stripe } from "@/server/stripe";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { z } from "zod"; import { z } from "zod";
const Request = z.object({ const Request = z.object({
run_id: z.string(), run_id: z.string(),
status: WorkflowRunStatusSchema.optional(), status: z
time: z.coerce.date().optional(), .enum(["not-started", "running", "uploading", "success", "failed"])
.optional(),
output_data: z.any().optional(), output_data: z.any().optional(),
}); });
export async function POST(request: Request) { export async function POST(request: Request) {
try { const [data, error] = await parseDataSafe(Request, request);
const [data, error] = await parseDataSafe(Request, request); if (!data || error) return error;
if (!data || error) return error; const { run_id, status, output_data } = data;
const { run_id, status, time, output_data } = data; // console.log(run_id, status, output_data);
if (status == "started" && time != undefined) { if (output_data) {
// It successfully started, update the started_at time const workflow_run_output = await db.insert(workflowRunOutputs).values({
await db run_id: run_id,
.update(workflowRunsTable) data: output_data,
.set({ });
started_at: time, } else if (status) {
}) // console.log("status", status);
.where(eq(workflowRunsTable.id, run_id)); const workflow_run = await db
} .update(workflowRunsTable)
.set({
if (status == "queued" && time != undefined) { status: status,
// It successfully started, update the started_at time ended_at:
await db status === "success" || status === "failed" ? new Date() : null,
.update(workflowRunsTable) })
.set({ .where(eq(workflowRunsTable.id, run_id))
queued_at: time, .returning();
})
.where(eq(workflowRunsTable.id, run_id));
}
if (output_data) {
const workflow_run_output = await db.insert(workflowRunOutputs).values({
run_id: run_id,
data: output_data,
});
} else if (status) {
const [workflow_run] = await db
.update(workflowRunsTable)
.set({
status: status,
ended_at:
status === "success" || status === "failed" ? new Date() : null,
})
.where(eq(workflowRunsTable.id, run_id))
.returning();
// Need to filter out only comfy deploy serverless
// Also multiply with the gpu selection
if (workflow_run.machine_type == "comfy-deploy-serverless") {
if (
(status === "success" || status === "failed") &&
workflow_run.user_id
) {
const sub = await getCurrentPlan({
user_id: workflow_run.user_id,
org_id: workflow_run.org_id,
});
if (sub && sub.subscription_item_api_id && workflow_run.ended_at) {
let durationInSec = Math.abs(
(workflow_run.ended_at.getTime() -
workflow_run.created_at.getTime()) /
1000,
);
durationInSec = Math.ceil(durationInSec);
switch (workflow_run.gpu) {
case "A100":
durationInSec *= 7;
break;
case "A10G":
durationInSec *= 4;
break;
}
await stripe.subscriptionItems.createUsageRecord(
sub.subscription_item_api_id,
{
quantity: durationInSec,
},
);
}
}
}
}
return NextResponse.json(
{
message: "success",
},
{
status: 200,
},
);
} catch (error: unknown) {
console.log("An error here");
const errorMessage =
error instanceof Error ? error.message : "Unknown error";
console.log(errorMessage);
return NextResponse.json(
{
error: errorMessage,
},
{
status: 500,
},
);
} }
// const workflow_version = await db.query.workflowVersionTable.findFirst({
// where: eq(workflowRunsTable.id, workflow_run[0].workflow_version_id),
// });
// revalidatePath(`./${workflow_version?.workflow_id}`);
return NextResponse.json(
{
message: "success",
},
{
status: 200,
}
);
} }
+63 -21
View File
@@ -1,14 +1,17 @@
import { snapshotType, workflowAPIType, workflowType } from "@/db/schema"; import { createNewWorkflow } from "../../../../server/createNewWorkflow";
import { parseJWT } from "../../../../server/parseJWT";
import { db } from "@/db/db";
import {
snapshotType,
workflowAPIType,
workflowTable,
workflowType,
workflowVersionTable,
} from "@/db/schema";
import { parseDataSafe } from "@/lib/parseDataSafe"; import { parseDataSafe } from "@/lib/parseDataSafe";
import { eq, sql } from "drizzle-orm";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { z } from "zod"; import { z } from "zod";
import {
createNewWorkflow,
createNewWorkflowVersion,
} from "../../../../server/createNewWorkflow";
import { parseJWT } from "../../../../server/parseJWT";
// This is will be deprecated
const corsHeaders = { const corsHeaders = {
"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Origin": "*",
@@ -52,7 +55,7 @@ export async function POST(request: Request) {
const [data, error] = await parseDataSafe( const [data, error] = await parseDataSafe(
UploadRequest, UploadRequest,
request, request,
corsHeaders, corsHeaders
); );
if (!data || error) return error; if (!data || error) return error;
@@ -72,7 +75,7 @@ export async function POST(request: Request) {
// Case 1 new workflow // Case 1 new workflow
try { try {
if ((!workflow_id || workflow_id.length === 0) && workflow_name) { if ((!workflow_id || workflow_id.length == 0) && workflow_name) {
// Create a new parent workflow // Create a new parent workflow
const { workflow_id: _workflow_id, version: _version } = const { workflow_id: _workflow_id, version: _version } =
await createNewWorkflow({ await createNewWorkflow({
@@ -88,17 +91,56 @@ export async function POST(request: Request) {
workflow_id = _workflow_id; workflow_id = _workflow_id;
version = _version; version = _version;
// const workflow_parent = await db
// .insert(workflowTable)
// .values({
// user_id,
// name: workflow_name,
// org_id: org_id,
// })
// .returning();
// workflow_id = workflow_parent[0].id;
// // Create a new version
// const data = await db
// .insert(workflowVersionTable)
// .values({
// workflow_id: workflow_id,
// workflow,
// workflow_api,
// version: 1,
// snapshot: snapshot,
// })
// .returning();
// version = data[0].version;
} else if (workflow_id) { } else if (workflow_id) {
// Case 2 update workflow // Case 2 update workflow
const { version: _version } = await createNewWorkflowVersion({ const data = await db
workflow_id: workflow_id, .insert(workflowVersionTable)
workflowData: { .values({
workflow, workflow_id,
workflow: workflow,
workflow_api, workflow_api,
snapshot, // version: sql`${workflowVersionTable.version} + 1`,
}, snapshot: snapshot,
}); version: sql`(
version = _version; SELECT COALESCE(MAX(version), 0) + 1
FROM ${workflowVersionTable}
WHERE workflow_id = ${workflow_id}
)`,
})
.returning();
version = data[0].version;
await db
.update(workflowTable)
.set({
updated_at: new Date(),
})
.where(eq(workflowTable.id, workflow_id))
.returning();
} else { } else {
return NextResponse.json( return NextResponse.json(
{ {
@@ -108,7 +150,7 @@ export async function POST(request: Request) {
status: 500, status: 500,
statusText: "Invalid request", statusText: "Invalid request",
headers: corsHeaders, headers: corsHeaders,
}, }
); );
} }
} catch (error: any) { } catch (error: any) {
@@ -120,7 +162,7 @@ export async function POST(request: Request) {
status: 500, status: 500,
statusText: "Invalid request", statusText: "Invalid request",
headers: corsHeaders, headers: corsHeaders,
}, }
); );
} }
@@ -132,6 +174,6 @@ export async function POST(request: Request) {
{ {
status: 200, status: 200,
headers: corsHeaders, headers: corsHeaders,
}, }
); );
} }
@@ -0,0 +1,50 @@
import { parseDataSafe } from "../../../../lib/parseDataSafe";
import { db } from "@/db/db";
import { checkpointTable, machinesTable } from "@/db/schema";
import { eq } from "drizzle-orm";
import { NextResponse } from "next/server";
import { z } from "zod";
const Request = z.object({
machine_id: z.string(),
endpoint: z.string().optional(),
build_log: z.string().optional(),
});
export async function POST(request: Request) {
const [data, error] = await parseDataSafe(Request, request);
if (!data || error) return error;
// console.log(data);
const { machine_id, endpoint, build_log } = data;
if (endpoint) {
await db
.update(checkpointTable)
.set({
// status: "ready",
// endpoint: endpoint,
// build_log: build_log,
})
.where(eq(machinesTable.id, machine_id));
} else {
// console.log(data);
await db
.update(machinesTable)
.set({
// status: "error",
// build_log: build_log,
})
.where(eq(machinesTable.id, machine_id));
}
return NextResponse.json(
{
message: "success",
},
{
status: 200,
}
);
}
@@ -1,55 +0,0 @@
import { parseDataSafe } from "../../../../lib/parseDataSafe";
import { db } from "@/db/db";
import { modelTable } from "@/db/schema";
import { eq } from "drizzle-orm";
import { NextResponse } from "next/server";
import { z } from "zod";
const Request = z.object({
volume_id: z.string(),
model_id: z.string(),
folder_path: z.string().optional(),
status: z.enum(["success", "failed"]),
error_log: z.string().optional(),
timeout: z.number().optional(),
});
export async function POST(request: Request) {
const [data, error] = await parseDataSafe(Request, request);
if (!data || error) return error;
const { model_id, error_log, status, folder_path } = data;
console.log(model_id, error_log, status, folder_path);
if (status === "success") {
await db
.update(modelTable)
.set({
status: "success",
folder_path,
updated_at: new Date(),
// build_log: build_log,
})
.where(eq(modelTable.id, model_id));
} else {
await db
.update(modelTable)
.set({
status: "failed",
error_log,
updated_at: new Date(),
// status: "error",
// build_log: build_log,
})
.where(eq(modelTable.id, model_id));
}
return NextResponse.json(
{
message: "success",
},
{
status: 200,
},
);
}
@@ -1,54 +0,0 @@
import { ButtonAction } from "@/components/ButtonActionLoader";
import { Button } from "@/components/ui/button";
import { createAuthRequest } from "@/server/curdApiKeys";
import { auth } from "@clerk/nextjs";
import { redirect } from "next/navigation";
import { getOrgOrUserDisplayName } from "../../../../server/getOrgOrUserDisplayName";
import { db } from "@/db/db";
import { eq } from "drizzle-orm";
import { authRequestsTable } from "@/db/schema";
export default async function Home({
params,
}: {
params: { request_id: string };
}) {
const { userId, orgId } = await auth();
if (!userId) redirect("/");
if (!params.request_id)
return (
<div className="h-full w-full flex flex-col gap-2 items-center justify-center">
No valid request_id
</div>
);
const existingResult = await db.query.authRequestsTable.findFirst({
where: eq(authRequestsTable.request_id, params.request_id),
});
if (existingResult?.api_hash) {
return (
<div className="h-full w-full flex flex-col gap-2 items-center justify-center">
Request already consumed.
</div>
);
}
const userName = await getOrgOrUserDisplayName(orgId, userId);
return (
<div className="h-full w-full flex flex-col gap-2 items-center justify-center">
<div className="text-lg">Grant API Access to {userName}</div>
<Button asChild>
<ButtonAction
routerAction="do-nothing"
action={createAuthRequest.bind(null, params.request_id)}
>
Grant Access
</ButtonAction>
</Button>
</div>
);
}
@@ -1,9 +0,0 @@
import { SignIn } from "@clerk/nextjs";
export default function Page() {
return (
<div className="w-full h-full items-center flex justify-center">
<SignIn />
</div>
);
}
@@ -1,9 +0,0 @@
import { SignUp } from "@clerk/nextjs";
export default function Page() {
return (
<div className="w-full h-full items-center flex justify-center">
<SignUp />
</div>
);
}
-9
View File
@@ -1,9 +0,0 @@
"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()} />;
}
-9
View File
@@ -1,9 +0,0 @@
import PricingList from "@/components/PricingPlan";
export default function Home() {
return (
<div>
<PricingList />
</div>
);
}
+8 -8
View File
@@ -1,19 +1,19 @@
// app/providers.tsx // app/providers.tsx
"use client"; 'use client'
import posthog from "posthog-js"; import posthog from 'posthog-js'
import { PostHogProvider } from "posthog-js/react"; import { PostHogProvider } from 'posthog-js/react'
if (typeof window !== "undefined") { if (typeof window !== 'undefined') {
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, { posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
capture_pageview: false, // Disable automatic pageview capture, as we capture manually capture_pageview: false // Disable automatic pageview capture, as we capture manually
}); })
} }
export function PHProvider({ export function PHProvider({
children, children,
}: { }: {
children: React.ReactNode; children: React.ReactNode
}) { }) {
return <PostHogProvider client={posthog}>{children}</PostHogProvider>; return <PostHogProvider client={posthog}>{children}</PostHogProvider>
} }
+81 -79
View File
@@ -2,11 +2,11 @@ import { ButtonActionMenu } from "@/components/ButtonActionLoader";
import { RunWorkflowInline } from "@/components/RunWorkflowInline"; import { RunWorkflowInline } from "@/components/RunWorkflowInline";
import { PublicRunOutputs } from "@/components/VersionSelect"; import { PublicRunOutputs } from "@/components/VersionSelect";
import { import {
Card, Card,
CardContent, CardContent,
CardDescription, CardDescription,
CardHeader, CardHeader,
CardTitle, CardTitle,
} from "@/components/ui/card"; } from "@/components/ui/card";
import { db } from "@/db/db"; import { db } from "@/db/db";
import { usersTable } from "@/db/schema"; import { usersTable } from "@/db/schema";
@@ -14,9 +14,9 @@ import { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow";
import { getRelativeTime } from "@/lib/getRelativeTime"; import { getRelativeTime } from "@/lib/getRelativeTime";
import { setInitialUserData } from "@/lib/setInitialUserData"; import { setInitialUserData } from "@/lib/setInitialUserData";
import { import {
cloneMachine, cloneMachine,
cloneWorkflow, cloneWorkflow,
findSharedDeployment, findSharedDeployment,
} from "@/server/curdDeploments"; } from "@/server/curdDeploments";
import { auth, clerkClient } from "@clerk/nextjs/server"; import { auth, clerkClient } from "@clerk/nextjs/server";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
@@ -25,87 +25,89 @@ import { redirect } from "next/navigation";
export const maxDuration = 300; // 5 minutes export const maxDuration = 300; // 5 minutes
export default async function Page({ export default async function Page({
params, params,
}: { }: {
params: { share_id: string }; params: { share_id: string };
}) { }) {
const { userId } = await auth(); const { userId } = await auth();
// If there is user, check if the user data is present // If there is user, check if the user data is present
if (userId) { if (userId) {
const user = await db.query.usersTable.findFirst({ const user = await db.query.usersTable.findFirst({
where: eq(usersTable.id, userId), where: eq(usersTable.id, userId),
}); });
if (!user) { if (!user) {
await setInitialUserData(userId); await setInitialUserData(userId);
} }
} }
const sharedDeployment = await findSharedDeployment(params.share_id); const sharedDeployment = await findSharedDeployment(params.share_id);
if (!sharedDeployment) return redirect("/"); if (!sharedDeployment) return redirect("/");
const userName = sharedDeployment.workflow.org_id const userName = sharedDeployment.workflow.org_id
? await clerkClient.organizations ? await clerkClient.organizations
.getOrganization({ .getOrganization({
organizationId: sharedDeployment.workflow.org_id, organizationId: sharedDeployment.workflow.org_id,
}) })
.then((x) => x.name) .then((x) => x.name)
: sharedDeployment.user.name; : sharedDeployment.user.name;
const inputs = getInputsFromWorkflow(sharedDeployment.version); const inputs = getInputsFromWorkflow(sharedDeployment.version);
return ( 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)]"> <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"> <Card className="w-full h-fit mt-4">
<CardHeader> <CardHeader>
<CardTitle className="flex justify-between items-center"> <CardTitle className="flex justify-between items-center">
<div> <div>
{userName} {userName}
{" / "} {" / "}
{sharedDeployment.workflow.name} {sharedDeployment.workflow.name}
</div> </div>
<ButtonActionMenu <ButtonActionMenu
title="Clone" title="Clone"
actions={[ actions={[
{ {
title: "Workflow", title: "Workflow",
action: cloneWorkflow.bind(null, sharedDeployment.id), action: cloneWorkflow.bind(null, sharedDeployment.id),
}, },
{ {
title: "Machine", title: "Machine",
action: cloneMachine.bind(null, sharedDeployment.id), action: cloneMachine.bind(null, sharedDeployment.id),
}, },
]} ]}
/> />
</CardTitle> </CardTitle>
<CardDescription suppressHydrationWarning={true}> <CardDescription suppressHydrationWarning={true}>
{getRelativeTime(sharedDeployment?.updated_at)} {getRelativeTime(sharedDeployment?.updated_at)}
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div> <div>
{sharedDeployment?.description && sharedDeployment?.description} {sharedDeployment?.description && (
</div> <>{sharedDeployment?.description}</>
<RunWorkflowInline )}
inputs={inputs} </div>
machine_id={sharedDeployment.machine_id} <RunWorkflowInline
workflow_version_id={sharedDeployment.workflow_version_id} inputs={inputs}
/> machine_id={sharedDeployment.machine_id}
</CardContent> workflow_version_id={sharedDeployment.workflow_version_id}
</Card> />
<Card className="w-full h-fit mt-4"> </CardContent>
<CardHeader> </Card>
<CardDescription>Run outputs</CardDescription> <Card className="w-full h-fit mt-4">
</CardHeader> <CardHeader>
<CardDescription>Run outputs</CardDescription>
</CardHeader>
<CardContent> <CardContent>
<PublicRunOutputs preview={sharedDeployment.showcase_media} /> <PublicRunOutputs preview={sharedDeployment.showcase_media} />
</CardContent> </CardContent>
</Card> </Card>
</div> </div>
); );
} }
+9 -9
View File
@@ -1,14 +1,14 @@
import { setInitialUserData } from "../../../lib/setInitialUserData"; import { setInitialUserData } from "../../../lib/setInitialUserData";
import { auth } from "@clerk/nextjs"; import { auth } from "@clerk/nextjs";
import { clerkClient } from "@clerk/nextjs/server"; import { clerkClient } from "@clerk/nextjs/server";
import { ModelList } from "@/components/ModelList"; import { CheckpointList } from "@/components/CheckpointList"
import { getAllUserModels } from "@/server/getAllUserModel"; import { getAllUserCheckpoints } from "@/server/getAllUserCheckpoints";
export default function Page() { export default function Page() {
return <ModelListServer />; return <CheckpointListServer />;
} }
async function ModelListServer() { async function CheckpointListServer() {
const { userId } = auth(); const { userId } = auth();
if (!userId) { if (!userId) {
@@ -20,16 +20,16 @@ async function ModelListServer() {
if (!user) { if (!user) {
await setInitialUserData(userId); await setInitialUserData(userId);
} }
const checkpoints = await getAllUserCheckpoints()
const models = await getAllUserModels(); if (!checkpoints) {
return <div>No checkpoints found</div>;
if (!models) {
return <div>No models found</div>;
} }
return ( return (
<div className="w-full"> <div className="w-full">
<ModelList data={models} /> <CheckpointList data={checkpoints}/>
</div> </div>
); );
} }
-9
View File
@@ -1,9 +0,0 @@
"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()} />;
}
-57
View File
@@ -1,57 +0,0 @@
import PricingList from "@/components/PricingPlan";
import { Badge } from "@/components/ui/badge";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Progress } from "@/components/ui/progress";
import { getCurrentPlanWithAuth } from "@/server/getCurrentPlan";
import { stripe } from "@/server/stripe";
const freeTierSeconds = 30000;
export default async function Home() {
const sub = await getCurrentPlanWithAuth();
const data = sub?.subscription_item_api_id
? await stripe.subscriptionItems.listUsageRecordSummaries(
sub?.subscription_item_api_id,
)
: null;
return (
<div className="mt-4 flex items-center justify-center">
<Card className="p-4 w-full max-w-[600px]">
<CardHeader>
<CardTitle>Account Usage</CardTitle>
<CardDescription>View you account usage</CardDescription>
<Badge className="w-fit">{sub?.plan}</Badge>
</CardHeader>
{data && (
<CardContent className="text-sm flex flex-col gap-2">
<div className="flex justify-between gap-2">
<span>Current free gpu usage:</span>
{
<div className="flex gap-2">
<Badge>
{data.data[0].total_usage}s /{Math.floor(freeTierSeconds)}s
</Badge>
<Badge>
{Math.floor(data.data[0].total_usage / 60 / 60)}hr /
{Math.floor(freeTierSeconds / 60 / 60)}hr
</Badge>
</div>
}
</div>
<Progress
value={(data.data[0].total_usage / freeTierSeconds) * 100}
></Progress>
</CardContent>
)}
</Card>
</div>
);
}
@@ -1,11 +1,10 @@
import { CreateShareButton } from "@/components/CreateShareButton";
import { MachinesWSMain } from "@/components/MachinesWS"; import { MachinesWSMain } from "@/components/MachinesWS";
import { VersionDetails } from "@/components/VersionDetails"; import { VersionDetails } from "@/components/VersionDetails";
import { import {
CopyWorkflowVersion, CopyWorkflowVersion,
CreateDeploymentButton, CreateDeploymentButton,
CreateShareButton,
MachineSelect, MachineSelect,
OpenEditButton,
RunWorkflowButton, RunWorkflowButton,
VersionSelect, VersionSelect,
ViewWorkflowDetailsButton, ViewWorkflowDetailsButton,
@@ -21,8 +20,6 @@ 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";
export const maxDuration = 300; // 5 minutes
export default async function Page({ export default async function Page({
params, params,
}: { }: {
@@ -51,7 +48,6 @@ export default async function Page({
<CreateShareButton workflow={workflow} machines={machines} /> <CreateShareButton workflow={workflow} machines={machines} />
<CopyWorkflowVersion workflow={workflow} /> <CopyWorkflowVersion workflow={workflow} />
<ViewWorkflowDetailsButton workflow={workflow} /> <ViewWorkflowDetailsButton workflow={workflow} />
<OpenEditButton workflow={workflow} machines={machines} />
</div> </div>
<VersionDetails workflow={workflow} /> <VersionDetails workflow={workflow} />
@@ -1,5 +1,3 @@
export const maxDuration = 300; // 5 minutes
export default async function Layout({ export default async function Layout({
children, children,
deployment, deployment,
+1 -3
View File
@@ -1,13 +1,11 @@
import { setInitialUserData } from "../../../lib/setInitialUserData"; import { setInitialUserData } from "../../../lib/setInitialUserData";
import { getAllUserWorkflow } from "../../../server/crudWorkflow"; import { getAllUserWorkflow } from "../../../server/getAllUserWorkflow";
import { WorkflowList } from "@/components/WorkflowList"; import { WorkflowList } from "@/components/WorkflowList";
import { db } from "@/db/db"; import { db } from "@/db/db";
import { usersTable } from "@/db/schema"; import { usersTable } from "@/db/schema";
import { auth } from "@clerk/nextjs"; import { auth } from "@clerk/nextjs";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
export const maxDuration = 300; // 5 minutes
export default function Home() { export default function Home() {
return <WorkflowServer />; return <WorkflowServer />;
} }
+1 -6
View File
@@ -17,11 +17,9 @@ import { useState } from "react";
export function ButtonAction({ export function ButtonAction({
action, action,
children, children,
routerAction = "back",
...rest ...rest
}: { }: {
action: () => Promise<any>; action: () => Promise<any>;
routerAction?: "refresh" | "back" | "do-nothing";
children: React.ReactNode; children: React.ReactNode;
}) { }) {
const [pending, setPending] = useState(false); const [pending, setPending] = useState(false);
@@ -36,10 +34,7 @@ export function ButtonAction({
await callServerPromise(action()); await callServerPromise(action());
setPending(false); setPending(false);
if (routerAction === "back") { router.refresh();
router.back();
router.refresh();
} else if (routerAction === "refresh") router.refresh();
}} }}
{...rest} {...rest}
> >
@@ -4,7 +4,7 @@ import { getRelativeTime } from "../lib/getRelativeTime";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox"; import { Checkbox } from "@/components/ui/checkbox";
import { InsertModal } from "./InsertModal"; import { InsertModal, UpdateModal } from "./InsertModal";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { ScrollArea } from "@/components/ui/scroll-area"; import { ScrollArea } from "@/components/ui/scroll-area";
import { import {
@@ -15,7 +15,7 @@ import {
TableHeader, TableHeader,
TableRow, TableRow,
} from "@/components/ui/table"; } from "@/components/ui/table";
import type { getAllUserModels as getAllUserModels } from "@/server/getAllUserModel"; import type { getAllUserCheckpoints } from "@/server/getAllUserCheckpoints";
import type { import type {
ColumnDef, ColumnDef,
ColumnFiltersState, ColumnFiltersState,
@@ -30,17 +30,17 @@ import {
getSortedRowModel, getSortedRowModel,
useReactTable, useReactTable,
} from "@tanstack/react-table"; } from "@tanstack/react-table";
import { ArrowUpDown } from "lucide-react"; import { ArrowUpDown, MoreHorizontal } from "lucide-react";
import * as React from "react"; import * as React from "react";
import { addCivitaiModel } from "@/server/curdModel"; import { insertCivitaiCheckpointSchema } from "@/db/schema";
import { addCivitaiModelSchema } from "@/server/addCivitaiModelSchema"; import { addCivitaiCheckpoint } from "@/server/curdCheckpoint";
import { modelEnumType } from "@/db/schema"; import { addCivitaiCheckpointSchema } from "@/server/addCheckpointSchema";
export type ModelItemList = NonNullable< export type CheckpointItemList = NonNullable<
Awaited<ReturnType<typeof getAllUserModels>> Awaited<ReturnType<typeof getAllUserCheckpoints>>
>[0]; >[0];
export const columns: ColumnDef<ModelItemList>[] = [ export const columns: ColumnDef<CheckpointItemList>[] = [
{ {
accessorKey: "id", accessorKey: "id",
id: "select", id: "select",
@@ -63,141 +63,50 @@ export const columns: ColumnDef<ModelItemList>[] = [
enableHiding: false, enableHiding: false,
}, },
{ {
accessorKey: "model_name", accessorKey: "name",
header: ({ column }) => { header: ({ column }) => {
return ( return (
<button <button
className="flex items-center hover:underline" className="flex items-center hover:underline"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")} onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
> >
Model Name Name
<ArrowUpDown className="ml-2 h-4 w-4" /> <ArrowUpDown className="ml-2 h-4 w-4" />
</button> </button>
); );
}, },
cell: ({ row }) => { cell: ({ row }) => {
const model = row.original; const checkpoint = row.original;
return ( return (
<> <a
{
/*<a
className="hover:underline flex gap-2" className="hover:underline flex gap-2"
href={`/storage/${model.id}`} // TODO href={`/storage/${checkpoint.id}`} // TODO
>*/ >
} <span className="truncate max-w-[200px]">{row.original.model_name}</span>
<span className="truncate max-w-[200px]">
{row.original.model_name}
</span>
{model.is_public <Badge variant="default">{}</Badge>
? <></> {checkpoint.is_public
: <Badge variant="orange">Private</Badge>} ? <Badge variant="success">Public</Badge>
</> : <Badge variant="teal">Private</Badge>}
</a>
); );
}, },
}, },
{ {
accessorKey: "status", accessorKey: "creator",
header: ({ column }) => { header: ({ column }) => {
return ( return (
<button <button
className="flex items-center hover:underline" className="flex items-center hover:underline"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")} onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
> >
Status Creator
<ArrowUpDown className="ml-2 h-4 w-4" /> <ArrowUpDown className="ml-2 h-4 w-4" />
</button> </button>
); );
}, },
cell: ({ row }) => { cell: ({ row }) => {
return ( // return <Badge variant="cyan">{row?.original?.user?.name ? row.original.user.name : "Public"}</Badge>;
<Badge
variant={row.original.status === "failed"
? "red"
: (row.original.status === "started" ? "yellow" : "green")}
>
{row.original.status}
</Badge>
);
// NOTE: retry downloads on failures
// const oneHourAgo = new Date(new Date().getTime() - (60 * 60 * 1000));
// const lastUpdated = new Date(row.original.updated_at);
// const canRefresh = row.original.status === "failed" && lastUpdated < oneHourAgo;
// const canRefresh = row.original.status === "failed" && lastUpdated < oneHourAgo;
// cell: ({ row }) => {
// // const oneHourAgo = new Date(new Date().getTime() - (60 * 60 * 1000));
// // const lastUpdated = new Date(row.original.updated_at);
// // const canRefresh = row.original.status === "failed" && lastUpdated < oneHourAgo;
// const canReDownload = true;
//
// return (
// <div className="flex items-center space-x-2">
// <Badge
// variant={row.original.status === "failed"
// ? "red"
// : row.original.status === "started"
// ? "yellow"
// : "green"}
// >
// {row.original.status}
// </Badge>
// {canReDownload && (
// <RefreshCcw
// onClick={() => {
// redownloadCheckpoint(row.original);
// }}
// className="h-4 w-4 cursor-pointer" // Adjust the size with h-x and w-x classes
// />
// )}
// </div>
// );
// },
},
},
{
accessorKey: "upload_type",
header: ({ column }) => {
return (
<button
className="flex items-center hover:underline"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
Source
<ArrowUpDown className="ml-2 h-4 w-4" />
</button>
);
},
cell: ({ row }) => {
return <Badge variant="cyan">{row.original.upload_type}</Badge>;
},
},
{
accessorKey: "model_type",
header: ({ column }) => {
return (
<button
className="flex items-center hover:underline"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
Model Type
<ArrowUpDown className="ml-2 h-4 w-4" />
</button>
);
},
cell: ({ row }) => {
const model_type_map: Record<modelEnumType, any> = {
"checkpoint": "amber",
"lora": "green",
"embedding": "violet",
"vae": "teal",
};
function getBadgeColor(modelType: modelEnumType) {
return model_type_map[modelType] || "default";
}
const color = getBadgeColor(row.original.model_type);
return <Badge variant={color}>{row.original.model_type}</Badge>;
}, },
}, },
{ {
@@ -222,7 +131,6 @@ export const columns: ColumnDef<ModelItemList>[] = [
</div> </div>
), ),
}, },
// TODO: deletion and editing for future sprint
// { // {
// id: "actions", // id: "actions",
// enableHiding: false, // enableHiding: false,
@@ -254,7 +162,7 @@ export const columns: ColumnDef<ModelItemList>[] = [
// }, // },
]; ];
export function ModelList({ data }: { data: ModelItemList[] }) { export function CheckpointList({ data }: { data: CheckpointItemList[] }) {
const [sorting, setSorting] = React.useState<SortingState>([]); const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>( const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[], [],
@@ -288,10 +196,9 @@ export function ModelList({ data }: { data: ModelItemList[] }) {
<div className="flex flex-row w-full items-center py-4"> <div className="flex flex-row w-full items-center py-4">
<Input <Input
placeholder="Filter workflows..." placeholder="Filter workflows..."
value={(table.getColumn("model_name")?.getFilterValue() as string) ?? value={(table.getColumn("name")?.getFilterValue() as string) ?? ""}
""}
onChange={(event) => onChange={(event) =>
table.getColumn("model_name")?.setFilterValue(event.target.value)} table.getColumn("name")?.setFilterValue(event.target.value)}
className="max-w-sm" className="max-w-sm"
/> />
<div className="ml-auto flex gap-2"> <div className="ml-auto flex gap-2">
@@ -302,17 +209,18 @@ export function ModelList({ data }: { data: ModelItemList[] }) {
// TODO: limitations based on plan // TODO: limitations based on plan
} }
tooltip={"Add models using their civitai url!"} tooltip={"Add models using their civitai url!"}
title="Add a Civitai Model" title="Civitai Checkpoint"
description="Pick a model from civitai" description="Pick a model from civitai"
serverAction={addCivitaiModel} serverAction={addCivitaiCheckpoint}
formSchema={addCivitaiModelSchema} formSchema={addCivitaiCheckpointSchema}
fieldConfig={{ fieldConfig={{
civitai_url: { civitai_url: {
fieldType: "fallback", fieldType: "fallback",
// fieldType: "fallback",
inputProps: { required: true }, inputProps: { required: true },
description: ( description: (
<> <>
Pick a model from{" "} Pick a checkpoint from{" "}
<a <a
href="https://www.civitai.com/models" href="https://www.civitai.com/models"
target="_blank" target="_blank"
-66
View File
@@ -1,66 +0,0 @@
"use client";
import { LoadingIcon } from "@/components/LoadingIcon";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { createDeployments } from "@/server/curdDeploments";
import type { getMachines } from "@/server/curdMachine";
import type { findFirstTableWithVersion } from "@/server/findFirstTableWithVersion";
import { Share } from "lucide-react";
import { parseAsInteger, useQueryState } from "next-usequerystate";
import { useState } from "react";
import { useSelectedMachine } from "./VersionSelect";
import { callServerPromise } from "./callServerPromise";
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>
);
}
+10 -11
View File
@@ -1,3 +1,4 @@
import { DeploymentRow, SharePageDeploymentRow } from "./DeploymentRow";
import { CodeBlock } from "@/components/CodeBlock"; import { CodeBlock } from "@/components/CodeBlock";
import { import {
Dialog, Dialog,
@@ -12,7 +13,6 @@ import { TableRow } from "@/components/ui/table";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow"; import { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow";
import type { findAllDeployments } from "@/server/findAllRuns"; import type { findAllDeployments } from "@/server/findAllRuns";
import { DeploymentRow, SharePageDeploymentRow } from "./DeploymentRow";
const curlTemplate = ` const curlTemplate = `
curl --request POST \ curl --request POST \
@@ -91,7 +91,7 @@ export function DeploymentDisplay({
}) { }) {
const workflowInput = getInputsFromWorkflow(deployment.version); const workflowInput = getInputsFromWorkflow(deployment.version);
if (deployment.environment === "public-share") { if (deployment.environment == "public-share") {
return <SharePageDeploymentRow deployment={deployment} />; return <SharePageDeploymentRow deployment={deployment} />;
} }
@@ -123,7 +123,6 @@ export function DeploymentDisplay({
href="https://github.com/BennyKok/comfyui-deploy-next-example/blob/main/src/lib/comfy-deploy.ts" href="https://github.com/BennyKok/comfyui-deploy-next-example/blob/main/src/lib/comfy-deploy.ts"
className="text-blue-500 hover:underline" className="text-blue-500 hover:underline"
target="_blank" target="_blank"
rel="noreferrer"
> >
here here
</a> </a>
@@ -136,7 +135,7 @@ export function DeploymentDisplay({
: jsClientSetupTemplate, : jsClientSetupTemplate,
deployment, deployment,
domain, domain,
workflowInput, workflowInput
)} )}
/> />
Create a run via deployment id Create a run via deployment id
@@ -148,7 +147,7 @@ export function DeploymentDisplay({
: jsClientCreateRunNoInputsTemplate, : jsClientCreateRunNoInputsTemplate,
deployment, deployment,
domain, domain,
workflowInput, workflowInput
)} )}
/> />
Check the status of the run, and retrieve the outputs Check the status of the run, and retrieve the outputs
@@ -157,7 +156,7 @@ export function DeploymentDisplay({
code={formatCode( code={formatCode(
clientTemplate_checkStatus, clientTemplate_checkStatus,
deployment, deployment,
domain, domain
)} )}
/> />
</TabsContent> </TabsContent>
@@ -195,7 +194,7 @@ function formatCode(
deployment: Awaited<ReturnType<typeof findAllDeployments>>[0], deployment: Awaited<ReturnType<typeof findAllDeployments>>[0],
domain: string, domain: string,
inputs?: ReturnType<typeof getInputsFromWorkflow>, inputs?: ReturnType<typeof getInputsFromWorkflow>,
inputsTabs?: number, inputsTabs?: number
) { ) {
if (inputs && inputs.length > 0) { if (inputs && inputs.length > 0) {
codeTemplate = codeTemplate.replace( codeTemplate = codeTemplate.replace(
@@ -204,20 +203,20 @@ function formatCode(
Object.fromEntries( Object.fromEntries(
inputs.map((x) => { inputs.map((x) => {
return [x?.input_id, ""]; return [x?.input_id, ""];
}), })
), ),
null, null,
2, 2
) )
.split("\n") .split("\n")
.map((line, index) => (index === 0 ? line : ` ${line}`)) // Add two spaces indentation except for the first line .map((line, index) => (index === 0 ? line : ` ${line}`)) // Add two spaces indentation except for the first line
.join("\n")}`, .join("\n")}`
); );
} else { } else {
codeTemplate = codeTemplate.replace( codeTemplate = codeTemplate.replace(
` `
inputs: {}`, inputs: {}`,
"", ""
); );
} }
return codeTemplate return codeTemplate
+44 -46
View File
@@ -6,57 +6,55 @@ import type { findAllDeployments } from "@/server/findAllRuns";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
export function SharePageDeploymentRow({ export function SharePageDeploymentRow({
deployment, deployment,
}: { }: {
deployment: Awaited<ReturnType<typeof findAllDeployments>>[0]; deployment: Awaited<ReturnType<typeof findAllDeployments>>[0];
}) { }) {
const router = useRouter(); const router = useRouter();
return ( return (
<TableRow <TableRow
className="appearance-none hover:cursor-pointer" className="appearance-none hover:cursor-pointer"
onClick={() => { onClick={() => {
if (deployment.environment === "public-share") { if (deployment.environment == "public-share") {
router.push( router.push(`/share/${deployment.id}/settings`);
`/share/${deployment.share_slug ?? deployment.id}/settings`, }
); }}
} >
}} <TableCell className="capitalize truncate">
> {deployment.environment}
<TableCell className="capitalize truncate"> </TableCell>
{deployment.environment} <TableCell className="font-medium truncate">
</TableCell> {deployment.version?.version}
<TableCell className="font-medium truncate"> </TableCell>
{deployment.version?.version} <TableCell className="font-medium truncate">
</TableCell> {deployment.machine?.name}
<TableCell className="font-medium truncate"> </TableCell>
{deployment.machine?.name} <TableCell className="text-right truncate">
</TableCell> {getRelativeTime(deployment.updated_at)}
<TableCell className="text-right truncate"> </TableCell>
{getRelativeTime(deployment.updated_at)} </TableRow>
</TableCell> );
</TableRow>
);
} }
export function DeploymentRow({ export function DeploymentRow({
deployment, deployment,
}: { }: {
deployment: Awaited<ReturnType<typeof findAllDeployments>>[0]; deployment: Awaited<ReturnType<typeof findAllDeployments>>[0];
}) { }) {
return ( return (
<> <>
<TableCell className="capitalize truncate"> <TableCell className="capitalize truncate">
{deployment.environment} {deployment.environment}
</TableCell> </TableCell>
<TableCell className="font-medium truncate"> <TableCell className="font-medium truncate">
{deployment.version?.version} {deployment.version?.version}
</TableCell> </TableCell>
<TableCell className="font-medium truncate"> <TableCell className="font-medium truncate">
{deployment.machine?.name} {deployment.machine?.name}
</TableCell> </TableCell>
<TableCell className="text-right truncate"> <TableCell className="text-right truncate">
{getRelativeTime(deployment.updated_at)} {getRelativeTime(deployment.updated_at)}
</TableCell> </TableCell>
</> </>
); );
} }
-60
View File
@@ -6,19 +6,6 @@ import { getConnectionStatus } from "@/components/getConnectionStatus";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import useWebSocket from "react-use-websocket"; import useWebSocket from "react-use-websocket";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
import { useRouter } from "next/navigation";
export function MachineBuildLog({ export function MachineBuildLog({
machine_id, machine_id,
endpoint, endpoint,
@@ -30,7 +17,6 @@ export function MachineBuildLog({
}) { }) {
const [logs, setLogs] = useState<LogsType>([]); const [logs, setLogs] = useState<LogsType>([]);
const [finished, setFinished] = useState(false); const [finished, setFinished] = useState(false);
const [status, setStatus] = useState<"failed" | "succuss">();
const wsEndpoint = endpoint.replace(/^http/, "ws"); const wsEndpoint = endpoint.replace(/^http/, "ws");
const query = { fly_instance_id: instance_id }; const query = { fly_instance_id: instance_id };
@@ -57,59 +43,13 @@ export function MachineBuildLog({
setLogs((logs) => [...(logs ?? []), message.data]); setLogs((logs) => [...(logs ?? []), message.data]);
} else if (message?.event === "FINISHED") { } else if (message?.event === "FINISHED") {
setFinished(true); setFinished(true);
setStatus(message.data.status)
} }
}, [lastMessage]); }, [lastMessage]);
const router = useRouter()
return ( return (
<div> <div>
{connectionStatus} {connectionStatus}
<LogsViewer logs={logs} /> <LogsViewer logs={logs} />
<AlertDialog open={finished}>
<AlertDialogContent>
{
status == "succuss" ? (
<>
<AlertDialogHeader>
<AlertDialogTitle>Machine Built</AlertDialogTitle>
<AlertDialogDescription>
Your machine is built, you can now integrate your API, or directly run to check this machines.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogAction onClick={() => {
router.push("/workflows")
}}>See Workflows</AlertDialogAction>
<AlertDialogAction onClick={() => {
router.push("/machines")
}}>See All Machines</AlertDialogAction>
</AlertDialogFooter></>
) : (
<>
<AlertDialogHeader>
<AlertDialogTitle>Machine Failed</AlertDialogTitle>
<AlertDialogDescription>
Something went wrong with the machine build, please check the log.
Possible cause could be conflits with custom nodes, build got stuck, timeout, or too many custom nodes installed.
Please attempt a rebuild or remove some of the custom nodes.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>See logs</AlertDialogCancel>
<AlertDialogAction onClick={() => {
router.push("/machines")
}}>Back to machines</AlertDialogAction>
</AlertDialogFooter></>
)
}
</AlertDialogContent>
</AlertDialog>
</div> </div>
); );
} }
+30 -51
View File
@@ -40,7 +40,6 @@ import {
updateCustomMachine, updateCustomMachine,
updateMachine, updateMachine,
} from "@/server/curdMachine"; } from "@/server/curdMachine";
import { editWorkflowOnMachine } from "@/server/editWorkflowOnMachine";
import type { import type {
ColumnDef, ColumnDef,
ColumnFiltersState, ColumnFiltersState,
@@ -58,7 +57,6 @@ import {
import { ArrowUpDown, MoreHorizontal } from "lucide-react"; import { ArrowUpDown, MoreHorizontal } from "lucide-react";
import * as React from "react"; import * as React from "react";
import { useState } from "react"; import { useState } from "react";
import { toast } from "sonner";
import type { z } from "zod"; import type { z } from "zod";
export type Machine = MachineType; export type Machine = MachineType;
@@ -115,18 +113,16 @@ export const columns: ColumnDef<Machine>[] = [
{row.original.status} <LoadingIcon /> {row.original.status} <LoadingIcon />
</Badge> </Badge>
)} )}
{!row.original.disabled && {!row.original.disabled && row.original.status && (
row.original.status && <Badge
row.original.status != "building" && ( variant={
<Badge row.original.status == "ready" ? "success" : "destructive"
variant={ }
row.original.status == "ready" ? "success" : "destructive" className="capitalize"
} >
className="capitalize" {row.original.status}
> </Badge>
{row.original.status} )}
</Badge>
)}
</div> </div>
// </a> // </a>
); );
@@ -196,9 +192,7 @@ export const columns: ColumnDef<Machine>[] = [
<DropdownMenuItem <DropdownMenuItem
className="text-destructive" className="text-destructive"
onClick={async () => { onClick={async () => {
callServerPromise(deleteMachine(machine.id), { callServerPromise(deleteMachine(machine.id));
loadingText: "Deleting machine",
});
}} }}
> >
Delete Machine Delete Machine
@@ -206,9 +200,7 @@ export const columns: ColumnDef<Machine>[] = [
{machine.disabled ? ( {machine.disabled ? (
<DropdownMenuItem <DropdownMenuItem
onClick={async () => { onClick={async () => {
callServerPromise(enableMachine(machine.id), { callServerPromise(enableMachine(machine.id));
loadingText: "Enabling machine",
});
}} }}
> >
Enable Machine Enable Machine
@@ -217,9 +209,7 @@ export const columns: ColumnDef<Machine>[] = [
<DropdownMenuItem <DropdownMenuItem
className="text-destructive" className="text-destructive"
onClick={async () => { onClick={async () => {
callServerPromise(disableMachine(machine.id), { callServerPromise(disableMachine(machine.id));
loadingText: "Disabling machine",
});
}} }}
> >
Disable Machine Disable Machine
@@ -227,33 +217,22 @@ export const columns: ColumnDef<Machine>[] = [
)} )}
{machine.type === "comfy-deploy-serverless" && ( {machine.type === "comfy-deploy-serverless" && (
<> <>
<DropdownMenuItem <DropdownMenuItem asChild>
onClick={async () => { <a
const url = await callServerPromise( target="_blank"
editWorkflowOnMachine(machine.id), href={machine.endpoint.replace(
{ "comfyui-api",
loadingText: "Getting machine url...", "comfyui-app"
}, )}
); >
if (url && typeof url !== "object") { Open ComfyUI
window.open(url, "_blank"); </a>
} else if (url && typeof url === "object" && url.error) {
console.error(url.error);
}
}}
>
Open ComfyUI
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
onClick={() => { onClick={() => {
callServerPromise( buildMachine({
buildMachine({ id: machine.id,
id: machine.id, });
}),
{
loadingText: "Starting machine build process",
},
);
}} }}
> >
Rebuild Rebuild
@@ -327,7 +306,7 @@ export function MachineList({
}) { }) {
const [sorting, setSorting] = React.useState<SortingState>([]); const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>( const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[], []
); );
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({}); React.useState<VisibilityState>({});
@@ -368,7 +347,7 @@ export function MachineList({
dialogClassName="sm:max-w-[600px]" dialogClassName="sm:max-w-[600px]"
disabled={ disabled={
data.some( data.some(
(machine) => machine.type === "comfy-deploy-serverless", (machine) => machine.type === "comfy-deploy-serverless"
) && !userMetadata.betaFeaturesAccess ) && !userMetadata.betaFeaturesAccess
} }
tooltip={ tooltip={
@@ -431,7 +410,7 @@ export function MachineList({
? null ? null
: flexRender( : flexRender(
header.column.columnDef.header, header.column.columnDef.header,
header.getContext(), header.getContext()
)} )}
</TableHead> </TableHead>
); );
@@ -450,7 +429,7 @@ export function MachineList({
<TableCell key={cell.id}> <TableCell key={cell.id}>
{flexRender( {flexRender(
cell.column.columnDef.cell, cell.column.columnDef.cell,
cell.getContext(), cell.getContext()
)} )}
</TableCell> </TableCell>
))} ))}
+11 -14
View File
@@ -22,7 +22,6 @@ import {
} from "@clerk/nextjs"; } from "@clerk/nextjs";
import { Github, Menu } from "lucide-react"; import { Github, Menu } from "lucide-react";
import meta from "next-gen/config"; import meta from "next-gen/config";
import { useFeatureFlagEnabled } from "posthog-js/react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useMediaQuery } from "usehooks-ts"; import { useMediaQuery } from "usehooks-ts";
@@ -30,12 +29,9 @@ export function Navbar() {
const { organization } = useOrganization(); const { organization } = useOrganization();
const _isDesktop = useMediaQuery("(min-width: 1024px)"); const _isDesktop = useMediaQuery("(min-width: 1024px)");
const [isDesktop, setIsDesktop] = useState(true); const [isDesktop, setIsDesktop] = useState(true);
useEffect(() => { useEffect(() => {
setIsDesktop(_isDesktop); setIsDesktop(_isDesktop);
}, [_isDesktop]); }, [_isDesktop]);
return ( return (
<> <>
<div className="flex flex-row items-center gap-4"> <div className="flex flex-row items-center gap-4">
@@ -52,6 +48,13 @@ export function Navbar() {
</SheetHeader> </SheetHeader>
<div className="grid h-full grid-rows-[1fr_auto]"> <div className="grid h-full grid-rows-[1fr_auto]">
<NavbarMenu className=" h-full" /> <NavbarMenu className=" h-full" />
{/* <OrganizationSwitcher
appearance={{
elements: {
rootBox: "flex items-center justify-center z-[50]",
},
}}
/> */}
<Popover> <Popover>
<PopoverTrigger asChild> <PopoverTrigger asChild>
<Button variant="outline"> <Button variant="outline">
@@ -82,26 +85,20 @@ export function Navbar() {
</div> </div>
<div className="flex flex-row items-center gap-2"> <div className="flex flex-row items-center gap-2">
{isDesktop && <NavbarMenu />} {isDesktop && <NavbarMenu />}
{/* <Button <Button
asChild asChild
variant="link" variant="link"
className="rounded-full aspect-square p-2 mr-4" className="rounded-full aspect-square p-2 mr-4"
> >
<a href="/docs">Docs</a> <a href="/docs">Docs</a>
</Button> */} </Button>
<UserButton <UserButton />
afterSignOutUrl="/"
/>
<Button <Button
asChild asChild
variant="outline" variant="outline"
className="rounded-full aspect-square p-2" className="rounded-full aspect-square p-2"
> >
<a <a target="_blank" href="https://github.com/BennyKok/comfyui-deploy">
target="_blank"
href="https://github.com/BennyKok/comfyui-deploy"
rel="noreferrer"
>
<Github /> <Github />
</a> </a>
</Button> </Button>
+2 -21
View File
@@ -6,7 +6,6 @@ import { cn } from "@/lib/utils";
import Link from "next/link"; import Link from "next/link";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useFeatureFlagEnabled } from "posthog-js/react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useMediaQuery } from "usehooks-ts"; import { useMediaQuery } from "usehooks-ts";
@@ -22,8 +21,6 @@ export function NavbarMenu({ className }: { className?: string }) {
const router = useRouter(); const router = useRouter();
const pricingPlanFlagEnable = useFeatureFlagEnabled("pricing-plan");
const pages = [ const pages = [
{ {
name: "Workflows", name: "Workflows",
@@ -43,31 +40,15 @@ export function NavbarMenu({ className }: { className?: string }) {
}, },
]; ];
if (pricingPlanFlagEnable) {
pages.push({
name: "Pricing",
path: "/pricing",
})
pages.push({
name: "Usage",
path: "/usage",
})
}
pages.push({
name: "Docs",
path: "/docs",
})
return ( return (
<div className={cn("mr-2", className)}> <div className={cn("mr-2", className)}>
{/* <div className="w-full h-full absolute inset-x-0 top-0 flex items-center justify-center pointer-events-none"> */} {/* <div className="w-full h-full absolute inset-x-0 top-0 flex items-center justify-center pointer-events-none"> */}
{isDesktop && ( {isDesktop && (
<Tabs <Tabs
defaultValue={pathname} defaultValue={pathname}
className="w-fit flex pointer-events-auto" className="w-[400px] flex pointer-events-auto"
> >
<TabsList className=" w-full "> <TabsList className="grid w-full grid-cols-4">
{pages.map((page) => ( {pages.map((page) => (
<TabsTrigger <TabsTrigger
key={page.name} key={page.name}
-411
View File
@@ -1,411 +0,0 @@
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
import { Check, Info, Minus } from "lucide-react";
import { Fragment } from "react";
import { auth } from "@clerk/nextjs";
import { getCurrentPlan } from "../server/getCurrentPlan";
const tiers = [
{
name: "Basic",
id: "basic",
// href: "/api/checkout?plan=basic",
href: "/workflows",
priceMonthly: "$0",
description: "Instant Comfy UI API",
mostPopular: false,
},
{
name: "Pro",
id: "pro",
href: "/api/stripe/checkout?plan=pro",
priceMonthly: "$20",
description: "Accelerate Comfy UI",
mostPopular: false,
},
{
name: "Enterprise",
id: "enterprise",
href: "/api/stripe/checkout?plan=enterprise",
priceMonthly: "$100",
description: "Scale your Products",
mostPopular: true,
},
];
type TierFeature = {
Basic?: string | JSX.Element | boolean;
Pro?: string | JSX.Element | boolean;
Enterprise?: string | JSX.Element | boolean;
};
type Feature = {
name: string;
tiers: TierFeature;
};
type Section = {
name: string;
features: Feature[];
};
const sections: Section[] = [
{
name: "Features",
features: [
{
name: "GPU",
tiers: { Basic: "T4", Pro: "T4, A10G", Enterprise: "T4, A10G, A100" },
},
{
name: "Compute Credit",
tiers: {
Basic: (
<Tooltip>
<TooltipTrigger className="flex items-center justify-center gap-2">
30k secs free + usage <Info size={14} />
</TooltipTrigger>
<TooltipContent>
<ul className="flex flex-col items-start justify-start">
GPU Price /s = $0.00015
<li>- T4 Multiplier = x1</li>
</ul>
</TooltipContent>
</Tooltip>
),
Pro: (
<Tooltip>
<TooltipTrigger className="flex items-center justify-center gap-2">
30k secs free + usage <Info size={14} />
</TooltipTrigger>
<TooltipContent>
<ul className="flex flex-col items-start justify-start">
GPU Price /s = $0.00015
<li>- T4 Multiplier = x1</li>
<li>- A10G Multiplier = x4</li>
</ul>
</TooltipContent>
</Tooltip>
),
Enterprise: (
<Tooltip>
<TooltipTrigger className="flex items-center justify-center gap-2">
30k secs free + usage <Info size={14} />
</TooltipTrigger>
<TooltipContent>
<ul className="flex flex-col items-start justify-start">
GPU Price /s = $0.00015
<li>- T4 Multiplier = x1</li>
<li>- A10G Multiplier = x4</li>
<li>- A100 Multiplier = x7</li>
</ul>
</TooltipContent>
</Tooltip>
),
},
},
{
name: "Workflows",
tiers: { Basic: "2", Pro: "25", Enterprise: "Unlimited" },
},
{
name: "Serverless Machines",
tiers: { Basic: "2", Pro: "10", Enterprise: "Unlimited" },
},
{
name: "Outputs Storage",
tiers: { Basic: "2 GB", Pro: "10 GB", Enterprise: "Unlimited" },
},
{
name: "Dedicated Support",
tiers: { Enterprise: true },
},
{
name: "Private Model Hosting",
tiers: { Enterprise: "Coming Soon" },
},
],
},
];
export default async function PricingList() {
const { userId, orgId } = auth();
if (!userId) {
return <>No user id</>;
}
const sub = await getCurrentPlan({ user_id: userId, org_id: orgId });
const getHrefFromTier = (tier: (typeof tiers)[0]) => {
if (sub?.status == "active") {
if (tier.id == sub?.plan) return "/api/stripe/dashboard";
// This is actually cancelled
if (sub.cancel_at_period_end) return tier.href;
return "/api/stripe/dashboard?change=true";
} else {
return tier.href;
}
};
const getNameFromTier = (tier: (typeof tiers)[0]) => {
if (tier.id == sub?.plan && sub.status == "active") {
return sub.cancel_at_period_end ? (
<>
Current <span className="text-2xs"> - Ending this period</span>
</>
) : (
"Current"
);
}
if (sub?.status == "active") {
return "Get Started";
} else {
return "Get Started";
}
};
return (
<div className="bg-white py-24 sm:py-32">
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-4xl text-center">
<h2 className="text-base font-semibold leading-7 text-indigo-600">
Pricing
</h2>
<p className="mt-2 text-4xl font-bold tracking-tight text-gray-900 sm:text-5xl">
Turn any workflow into API
</p>
</div>
<p className="mx-auto mt-6 max-w-2xl text-center text-lg leading-8 text-gray-600">
ComfyDeploy is now under technical preview.
</p>
{/* xs to lg */}
<div className="mx-auto mt-12 max-w-md space-y-8 sm:mt-16 lg:hidden">
{tiers.map((tier) => (
<section
key={tier.id}
className={cn(
tier.mostPopular
? "rounded-xl bg-gray-400/5 ring-1 ring-inset ring-gray-200"
: "",
"p-8",
)}
>
<h3
id={tier.id}
className="text-sm font-semibold leading-6 text-gray-900"
>
{tier.name}
</h3>
<p className="mt-2 flex items-baseline gap-x-1 text-gray-900">
<span className="text-4xl font-bold">{tier.priceMonthly}</span>
<span className="text-sm font-semibold">/month</span>
</p>
<br></br>
<div className="text-xl font-semibold">{tier.description}</div>
<a
href={getHrefFromTier(tier)}
aria-describedby={tier.id}
className={cn(
tier.mostPopular
? "bg-indigo-600 text-white hover:bg-indigo-500"
: "text-indigo-600 ring-1 ring-inset ring-indigo-200 hover:ring-indigo-300",
"mt-8 block rounded-md py-2 px-3 text-center text-sm font-semibold leading-6 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600",
)}
>
{getNameFromTier(tier)}
</a>
<ul
role="list"
className="mt-10 space-y-4 text-sm leading-6 text-gray-900"
>
{sections.map((section) => (
<li key={section.name}>
<ul role="list" className="space-y-4">
{section.features.map((feature) =>
feature.tiers[tier.name as keyof TierFeature] ? (
<li key={feature.name} className="flex gap-x-3">
<Check
className="h-6 w-5 flex-none text-indigo-600"
aria-hidden="true"
/>
<span>
{feature.name}{" "}
{typeof feature.tiers[
tier.name as keyof TierFeature
] === "string" ? (
<span className="text-sm leading-6 text-gray-500">
(
{
feature.tiers[
tier.name as keyof TierFeature
]
}
)
</span>
) : null}
</span>
</li>
) : null,
)}
</ul>
</li>
))}
</ul>
</section>
))}
</div>
{/* lg+ */}
<div className="isolate mt-20 hidden lg:block border-gray-100 border p-6 shadow-md rounded-lg">
<div className="relative -mx-8">
{tiers.some((tier) => tier.mostPopular) ? (
<div className="absolute inset-x-4 inset-y-0 -z-10 flex">
<div
className="flex w-1/4 px-4"
aria-hidden="true"
style={{
marginLeft: `${
(tiers.findIndex((tier) => tier.mostPopular) + 1) * 25
}%`,
}}
>
<div className="w-full rounded-t-xl border-x border-t border-gray-900/10 bg-gray-400/5" />
</div>
</div>
) : null}
<table className="w-full table-fixed border-separate border-spacing-x-8 text-left">
<caption className="sr-only">Pricing plan comparison</caption>
<colgroup>
<col className="w-1/4" />
<col className="w-1/4" />
<col className="w-1/4" />
<col className="w-1/4" />
</colgroup>
<thead>
<tr>
<td />
{tiers.map((tier) => (
<th
key={tier.id}
scope="col"
className="px-6 pt-6 xl:px-8 xl:pt-8"
>
<div className="text-sm font-semibold leading-7 text-gray-900">
{tier.name}
</div>
</th>
))}
</tr>
</thead>
<tbody>
<tr>
<th scope="row">
<span className="sr-only">Price</span>
</th>
{tiers.map((tier) => (
<td key={tier.id} className="px-6 pt-2 xl:px-8">
<div className="flex items-baseline gap-x-1 text-gray-900">
<span className="text-4xl font-bold">
{tier.priceMonthly}
</span>
<span className="text-sm font-semibold leading-6">
/month
</span>
</div>
<br></br>
<div className="text-md font-semibold">
{tier.description}
</div>
<a
href={getHrefFromTier(tier)}
className={cn(
tier.mostPopular
? "bg-indigo-600 text-white hover:bg-indigo-500"
: "text-indigo-600 ring-1 ring-inset ring-indigo-200 hover:ring-indigo-300",
"mt-8 block rounded-md py-2 px-3 text-center text-sm font-semibold leading-6 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600",
)}
>
{getNameFromTier(tier)}
</a>
</td>
))}
</tr>
{sections.map((section, sectionIdx) => (
<Fragment key={section.name}>
<tr>
<th
scope="colgroup"
colSpan={4}
className={cn(
sectionIdx === 0 ? "pt-8" : "pt-16",
"pb-4 text-sm font-semibold leading-6 text-gray-900",
)}
>
{section.name}
<div className="absolute inset-x-8 mt-4 h-px bg-gray-900/10" />
</th>
</tr>
{section.features.map((feature) => (
<tr key={feature.name}>
<th
scope="row"
className="py-4 text-sm font-normal leading-6 text-gray-900"
>
{feature.name}
<div className="absolute inset-x-8 mt-4 h-px bg-gray-900/5" />
</th>
{tiers.map((tier) => (
<td key={tier.id} className="px-6 py-4 xl:px-8">
{typeof feature.tiers[
tier.name as keyof TierFeature
] === "string" ||
typeof feature.tiers[
tier.name as keyof TierFeature
] === "object" ? (
<div className="flex items-center justify-center text-center text-sm leading-6 text-gray-500">
{feature.tiers[tier.name as keyof TierFeature]}
</div>
) : (
<>
{feature.tiers[
tier.name as keyof TierFeature
] === true ? (
<Check
className="mx-auto h-5 w-5 text-indigo-600"
aria-hidden="true"
/>
) : (
<Minus
className="mx-auto h-5 w-5 text-gray-400"
aria-hidden="true"
/>
)}
<span className="sr-only">
{feature.tiers[
tier.name as keyof TierFeature
] === true
? "Included"
: "Not included"}{" "}
in {tier.name}
</span>
</>
)}
</td>
))}
</tr>
))}
</Fragment>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
);
}
+3 -24
View File
@@ -1,3 +1,4 @@
import { LiveStatus } from "./LiveStatus";
import { RunInputs } from "@/components/RunInputs"; import { RunInputs } from "@/components/RunInputs";
import { RunOutputs } from "@/components/RunOutputs"; import { RunOutputs } from "@/components/RunOutputs";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
@@ -10,15 +11,9 @@ import {
DialogTrigger, DialogTrigger,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { TableCell, TableRow } from "@/components/ui/table"; import { TableCell, TableRow } from "@/components/ui/table";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { getDuration, getRelativeTime } from "@/lib/getRelativeTime"; import { getDuration, getRelativeTime } from "@/lib/getRelativeTime";
import { type findAllRuns } from "@/server/findAllRuns"; import { type findAllRuns } from "@/server/findAllRuns";
import { Suspense } from "react"; import { Suspense } from "react";
import { LiveStatus } from "./LiveStatus";
export async function RunDisplay({ export async function RunDisplay({
run, run,
@@ -29,12 +24,7 @@ export async function RunDisplay({
<Dialog> <Dialog>
<DialogTrigger asChild className="appearance-none hover:cursor-pointer"> <DialogTrigger asChild className="appearance-none hover:cursor-pointer">
<TableRow> <TableRow>
<TableCell> <TableCell>{run.number}</TableCell>
<Tooltip>
<TooltipTrigger>{run.number}</TooltipTrigger>
<TooltipContent>{run.id}</TooltipContent>
</Tooltip>
</TableCell>
<TableCell className="font-medium truncate"> <TableCell className="font-medium truncate">
{run.machine?.name} {run.machine?.name}
</TableCell> </TableCell>
@@ -48,18 +38,7 @@ export async function RunDisplay({
</Badge> </Badge>
</TableCell> </TableCell>
<TableCell className="truncate"> <TableCell className="truncate">
<Tooltip> {getDuration(run.duration)}
<TooltipTrigger>{getDuration(run.duration)}</TooltipTrigger>
<TooltipContent>
<div>
Serverless latency: {getDuration(run.comfy_deploy_cold_start)}
</div>
<div>
GPU Cold start: {getDuration(run.cold_start_duration)}
</div>
<div>Run duration: {getDuration(run.run_duration)}</div>
</TooltipContent>
</Tooltip>
</TableCell> </TableCell>
<LiveStatus run={run} /> <LiveStatus run={run} />
</TableRow> </TableRow>
+40 -40
View File
@@ -1,3 +1,10 @@
import {
findAllDeployments,
findAllRunsWithCounts,
} from "../server/findAllRuns";
import { DeploymentDisplay } from "./DeploymentDisplay";
import { PaginationControl } from "./PaginationControl";
import { RunDisplay } from "./RunDisplay";
import { import {
Table, Table,
TableBody, TableBody,
@@ -8,13 +15,6 @@ import {
} from "@/components/ui/table"; } from "@/components/ui/table";
import { parseAsInteger } from "next-usequerystate"; import { parseAsInteger } from "next-usequerystate";
import { headers } from "next/headers"; import { headers } from "next/headers";
import {
findAllDeployments,
findAllRunsWithCounts,
} from "../server/findAllRuns";
import { DeploymentDisplay } from "./DeploymentDisplay";
import { PaginationControl } from "./PaginationControl";
import { RunDisplay } from "./RunDisplay";
const itemPerPage = 6; const itemPerPage = 6;
const pageParser = parseAsInteger.withDefault(1); const pageParser = parseAsInteger.withDefault(1);
@@ -33,40 +33,40 @@ export async function RunsTable(props: {
offset: (page - 1) * itemPerPage, offset: (page - 1) * itemPerPage,
}); });
return ( return (
<div> <div>
<div className="overflow-auto h-fit w-full"> <div className="overflow-auto h-fit w-full">
<Table className=""> <Table className="">
{allRuns.length === 0 && ( {allRuns.length == 0 && (
<TableCaption>A list of your recent runs.</TableCaption> <TableCaption>A list of your recent runs.</TableCaption>
)} )}
<TableHeader className="bg-background top-0 sticky"> <TableHeader className="bg-background top-0 sticky">
<TableRow> <TableRow>
<TableHead className="truncate">Number</TableHead> <TableHead className="truncate">Number</TableHead>
<TableHead className="truncate">Machine</TableHead> <TableHead className="truncate">Machine</TableHead>
<TableHead className="truncate">Time</TableHead> <TableHead className="truncate">Time</TableHead>
<TableHead className="truncate">Version</TableHead> <TableHead className="truncate">Version</TableHead>
<TableHead className="truncate">Origin</TableHead> <TableHead className="truncate">Origin</TableHead>
<TableHead className="truncate">Duration</TableHead> <TableHead className="truncate">Duration</TableHead>
<TableHead className="truncate">Live Status</TableHead> <TableHead className="truncate">Live Status</TableHead>
<TableHead className="text-right">Status</TableHead> <TableHead className="text-right">Status</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
{allRuns.map((run) => ( {allRuns.map((run) => (
<RunDisplay run={run} key={run.id} /> <RunDisplay run={run} key={run.id} />
))} ))}
</TableBody> </TableBody>
</Table> </Table>
</div> </div>
{Math.ceil(total / itemPerPage) > 0 && ( {Math.ceil(total / itemPerPage) > 0 && (
<PaginationControl <PaginationControl
totalPage={Math.ceil(total / itemPerPage)} totalPage={Math.ceil(total / itemPerPage)}
currentPage={page} currentPage={page}
/> />
)} )}
</div> </div>
); );
} }
export async function DeploymentsTable(props: { workflow_id: string }) { export async function DeploymentsTable(props: { workflow_id: string }) {
+2 -3
View File
@@ -1,5 +1,6 @@
"use client"; "use client";
import { useServerActionData } from "./useServerActionData";
import { ButtonAction } from "@/components/ButtonActionLoader"; import { ButtonAction } from "@/components/ButtonActionLoader";
import { UpdateModal } from "@/components/InsertModal"; import { UpdateModal } from "@/components/InsertModal";
import { LoadingPageWrapper } from "@/components/LoadingWrapper"; import { LoadingPageWrapper } from "@/components/LoadingWrapper";
@@ -14,7 +15,6 @@ import { ExternalLink } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { useServerActionData } from "./useServerActionData";
export function SharePageSettings({ export function SharePageSettings({
deployment_id, deployment_id,
@@ -58,14 +58,13 @@ export function SharePageSettings({
type="button" type="button"
> >
<ButtonAction <ButtonAction
routerAction="back"
action={removePublicShareDeployment.bind(null, deployment.id)} action={removePublicShareDeployment.bind(null, deployment.id)}
> >
Remove Remove
</ButtonAction> </ButtonAction>
</Button> </Button>
<Button asChild className="gap-2 truncate" type="button"> <Button asChild className="gap-2 truncate" type="button">
<Link href={`/share/${deployment.share_slug ?? deployment.id}`} target="_blank"> <Link href={`/share/${deployment.id}`} target="_blank">
View Share Page <ExternalLink size={14} /> View Share Page <ExternalLink size={14} />
</Link> </Link>
</Button> </Button>
+53 -52
View File
@@ -1,5 +1,8 @@
"use client"; "use client";
import { workflowVersionInputsToZod } from "../lib/workflowVersionInputsToZod";
import { callServerPromise } from "./callServerPromise";
import fetcher from "./fetcher";
import { LoadingIcon } from "@/components/LoadingIcon"; import { LoadingIcon } from "@/components/LoadingIcon";
import AutoForm, { AutoFormSubmit } from "@/components/ui/auto-form"; import AutoForm, { AutoFormSubmit } from "@/components/ui/auto-form";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
@@ -43,11 +46,11 @@ import type { getMachines } from "@/server/curdMachine";
import type { findFirstTableWithVersion } from "@/server/findFirstTableWithVersion"; import type { findFirstTableWithVersion } from "@/server/findFirstTableWithVersion";
import { import {
Copy, Copy,
Edit,
ExternalLink, ExternalLink,
Info, Info,
MoreVertical, MoreVertical,
Play, Play,
Share,
} from "lucide-react"; } from "lucide-react";
import { parseAsInteger, useQueryState } from "next-usequerystate"; import { parseAsInteger, useQueryState } from "next-usequerystate";
import { useEffect, useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
@@ -55,11 +58,6 @@ import { toast } from "sonner";
import useSWR from "swr"; import useSWR from "swr";
import type { z } from "zod"; import type { z } from "zod";
import { create } from "zustand"; import { create } from "zustand";
import { workflowVersionInputsToZod } from "../lib/workflowVersionInputsToZod";
import { callServerPromise } from "./callServerPromise";
import fetcher from "./fetcher";
import { ButtonAction } from "@/components/ButtonActionLoader";
import { editWorkflowOnMachine } from "@/server/editWorkflowOnMachine";
export function VersionSelect({ export function VersionSelect({
workflow, workflow,
@@ -124,9 +122,7 @@ export function MachineSelect({
); );
} }
export function useSelectedMachine( function useSelectedMachine(machines: Awaited<ReturnType<typeof getMachines>>) {
machines: Awaited<ReturnType<typeof getMachines>>,
) {
const a = useQueryState("machine", { const a = useQueryState("machine", {
defaultValue: machines?.[0]?.id ?? "", defaultValue: machines?.[0]?.id ?? "",
}); });
@@ -228,7 +224,7 @@ export function RunWorkflowButton({
const schema = useMemo(() => { const schema = useMemo(() => {
const workflow_version = getWorkflowVersionFromVersionIndex( const workflow_version = getWorkflowVersionFromVersionIndex(
workflow, workflow,
version, version
); );
if (!workflow_version) return null; if (!workflow_version) return null;
@@ -242,7 +238,7 @@ export function RunWorkflowButton({
const val = Object.keys(values).length > 0 ? values : undefined; const val = Object.keys(values).length > 0 ? values : undefined;
const workflow_version_id = workflow?.versions.find( const workflow_version_id = workflow?.versions.find(
(x) => x.version === version, (x) => x.version === version
)?.id; )?.id;
console.log(workflow_version_id); console.log(workflow_version_id);
if (!workflow_version_id) return; if (!workflow_version_id) return;
@@ -257,7 +253,7 @@ export function RunWorkflowButton({
machine_id: machine, machine_id: machine,
inputs: val, inputs: val,
runOrigin: "manual", runOrigin: "manual",
}), })
); );
// console.log(res.json()); // console.log(res.json());
setIsLoading(false); setIsLoading(false);
@@ -326,7 +322,7 @@ export function CreateDeploymentButton({
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const workflow_version_id = workflow?.versions.find( const workflow_version_id = workflow?.versions.find(
(x) => x.version === version, (x) => x.version === version
)?.id; )?.id;
return ( return (
<DropdownMenu> <DropdownMenu>
@@ -346,8 +342,8 @@ export function CreateDeploymentButton({
workflow.id, workflow.id,
workflow_version_id, workflow_version_id,
machine, machine,
"production", "production"
), )
); );
setIsLoading(false); setIsLoading(false);
}} }}
@@ -364,8 +360,8 @@ export function CreateDeploymentButton({
workflow.id, workflow.id,
workflow_version_id, workflow_version_id,
machine, machine,
"staging", "staging"
), )
); );
setIsLoading(false); setIsLoading(false);
}} }}
@@ -377,7 +373,7 @@ export function CreateDeploymentButton({
); );
} }
export function OpenEditButton({ export function CreateShareButton({
workflow, workflow,
machines, machines,
}: { }: {
@@ -389,34 +385,40 @@ export function OpenEditButton({
...parseAsInteger, ...parseAsInteger,
}); });
const [machine] = useSelectedMachine(machines); const [machine] = useSelectedMachine(machines);
const workflow_version_id = workflow?.versions.find(
(x) => x.version == version,
)?.id;
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const workflow_version_id = workflow?.versions.find(
(x) => x.version === version
)?.id;
return ( return (
workflow_version_id && <DropdownMenu>
machine && ( <DropdownMenuTrigger asChild>
<Button <Button className="gap-2" disabled={isLoading} variant="outline">
className="gap-2" Share {isLoading ? <LoadingIcon /> : <Share size={14} />}
onClick={async () => { </Button>
setIsLoading(true); </DropdownMenuTrigger>
const url = await callServerPromise( <DropdownMenuContent className="w-56">
editWorkflowOnMachine(machine, workflow_version_id), <DropdownMenuItem
); onClick={async () => {
if (url && typeof url !== "object") { if (!workflow_version_id) return;
window.open(url, "_blank");
} else if (url && typeof url === "object" && url.error) { setIsLoading(true);
console.error(url.error); await callServerPromise(
} createDeployments(
setIsLoading(false); workflow.id,
}} workflow_version_id,
// asChild machine,
variant="outline" "public-share"
> )
Edit {isLoading ? <LoadingIcon /> : <Edit size={14} />} );
</Button> setIsLoading(false);
) }}
>
Public
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
); );
} }
@@ -430,7 +432,7 @@ export function CopyWorkflowVersion({
...parseAsInteger, ...parseAsInteger,
}); });
const workflow_version = workflow?.versions.find( const workflow_version = workflow?.versions.find(
(x) => x.version === version, (x) => x.version === version
); );
return ( return (
<DropdownMenu> <DropdownMenu>
@@ -454,7 +456,7 @@ export function CopyWorkflowVersion({
}); });
navigator.clipboard.writeText( navigator.clipboard.writeText(
JSON.stringify(workflow_version?.workflow), JSON.stringify(workflow_version?.workflow)
); );
toast("Copied to clipboard"); toast("Copied to clipboard");
}} }}
@@ -464,7 +466,7 @@ export function CopyWorkflowVersion({
<DropdownMenuItem <DropdownMenuItem
onClick={async () => { onClick={async () => {
navigator.clipboard.writeText( navigator.clipboard.writeText(
JSON.stringify(workflow_version?.workflow_api), JSON.stringify(workflow_version?.workflow_api)
); );
toast("Copied to clipboard"); toast("Copied to clipboard");
}} }}
@@ -478,7 +480,7 @@ export function CopyWorkflowVersion({
export function getWorkflowVersionFromVersionIndex( export function getWorkflowVersionFromVersionIndex(
workflow: Awaited<ReturnType<typeof findFirstTableWithVersion>>, workflow: Awaited<ReturnType<typeof findFirstTableWithVersion>>,
version: number, version: number
) { ) {
const workflow_version = workflow?.versions.find((x) => x.version == version); const workflow_version = workflow?.versions.find((x) => x.version == version);
@@ -504,7 +506,7 @@ export function ViewWorkflowDetailsButton({
isLoading: isNodesIndexLoading, isLoading: isNodesIndexLoading,
} = useSWR( } = useSWR(
"https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/extension-node-map.json", "https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/extension-node-map.json",
fetcher, fetcher
); );
const groupedByAuxName = useMemo(() => { const groupedByAuxName = useMemo(() => {
@@ -514,7 +516,7 @@ export function ViewWorkflowDetailsButton({
const workflow_version = getWorkflowVersionFromVersionIndex( const workflow_version = getWorkflowVersionFromVersionIndex(
workflow, workflow,
version, version
); );
const api = workflow_version?.workflow_api; const api = workflow_version?.workflow_api;
@@ -525,7 +527,7 @@ export function ViewWorkflowDetailsButton({
.map(([_, value]) => { .map(([_, value]) => {
const classType = value.class_type; const classType = value.class_type;
const classTypeData = Object.entries(data).find(([_, nodeArray]) => const classTypeData = Object.entries(data).find(([_, nodeArray]) =>
nodeArray[0].includes(classType), nodeArray[0].includes(classType)
); );
return classTypeData ? { node: value, classTypeData } : null; return classTypeData ? { node: value, classTypeData } : null;
}) })
@@ -555,7 +557,7 @@ export function ViewWorkflowDetailsButton({
node: z.infer<typeof workflowAPINodeType>[]; node: z.infer<typeof workflowAPINodeType>[];
url: string; url: string;
} }
>, >
); );
// console.log(groupedByAuxName); // console.log(groupedByAuxName);
@@ -597,7 +599,6 @@ export function ViewWorkflowDetailsButton({
href={group.url} href={group.url}
target="_blank" target="_blank"
className="hover:underline" className="hover:underline"
rel="noreferrer"
> >
{key} {key}
<ExternalLink <ExternalLink
+4 -4
View File
@@ -21,8 +21,8 @@ import {
TableHeader, TableHeader,
TableRow, TableRow,
} from "@/components/ui/table"; } from "@/components/ui/table";
import { getAllUserWorkflow } from "@/server/crudWorkflow";
import { deleteWorkflow } from "@/server/deleteWorkflow"; import { deleteWorkflow } from "@/server/deleteWorkflow";
import type { getAllUserWorkflow } from "@/server/getAllUserWorkflow";
import type { import type {
ColumnDef, ColumnDef,
ColumnFiltersState, ColumnFiltersState,
@@ -169,7 +169,7 @@ export const columns: ColumnDef<WorkflowItemList>[] = [
export function WorkflowList({ data }: { data: WorkflowItemList[] }) { export function WorkflowList({ data }: { data: WorkflowItemList[] }) {
const [sorting, setSorting] = React.useState<SortingState>([]); const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>( const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[], []
); );
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({}); React.useState<VisibilityState>({});
@@ -218,7 +218,7 @@ export function WorkflowList({ data }: { data: WorkflowItemList[] }) {
? null ? null
: flexRender( : flexRender(
header.column.columnDef.header, header.column.columnDef.header,
header.getContext(), header.getContext()
)} )}
</TableHead> </TableHead>
); );
@@ -237,7 +237,7 @@ export function WorkflowList({ data }: { data: WorkflowItemList[] }) {
<TableCell key={cell.id}> <TableCell key={cell.id}>
{flexRender( {flexRender(
cell.column.columnDef.cell, cell.column.columnDef.cell,
cell.getContext(), cell.getContext()
)} )}
</TableCell> </TableCell>
))} ))}

Some files were not shown because too many files have changed in this diff Show More