Compare commits
79
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9834dc0b25 | ||
|
|
1939ff4153 | ||
|
|
2b8272bd86 | ||
|
|
ccc9508664 | ||
|
|
b97e523e01 | ||
|
|
ec525e78ad | ||
|
|
4c32248d86 | ||
|
|
5ddbfdf44b | ||
|
|
5fcd43aa54 | ||
|
|
141d30aaa1 | ||
|
|
7e86c20383 | ||
|
|
3adf77617b | ||
|
|
1bc62a5fb4 | ||
|
|
d473a211d0 | ||
|
|
3aa239e58d | ||
|
|
223aa5e70b | ||
|
|
5eef60a4eb | ||
|
|
de750995cb | ||
|
|
0f58fbcebd | ||
|
|
6dc964c425 | ||
|
|
4171c08413 | ||
|
|
4348ab45dc | ||
|
|
df46e3a0e5 | ||
|
|
2772101bbf | ||
|
|
72fee51d32 | ||
|
|
ffe0f98360 | ||
|
|
68377a84bc | ||
|
|
50d4c399e9 | ||
|
|
5a3955dfcb | ||
|
|
03227b52c0 | ||
|
|
8a8fbccfaa | ||
|
|
018d9a7b8d | ||
|
|
774fd566d1 | ||
|
|
b81fcae6fb | ||
|
|
b6b34c9062 | ||
|
|
f73baa091a | ||
|
|
a838cb7ad4 | ||
|
|
2afcade4f2 | ||
|
|
d70333baa6 | ||
|
|
43cfebd97a | ||
|
|
763d2f77ce | ||
|
|
f1b68164c6 | ||
|
|
6437de4def | ||
|
|
b24bdb070e | ||
|
|
33b57aea34 | ||
|
|
71dcbe0d11 | ||
|
|
8e3ee6468f | ||
|
|
b8f39239ba | ||
|
|
9296f8f703 | ||
|
|
6ed7807081 | ||
|
|
43fe0a384a | ||
|
|
dae6e46a8e | ||
|
|
f7f3d9708b | ||
|
|
52d6e07eeb | ||
|
|
f64c242ee5 | ||
|
|
c0450b58d5 | ||
|
|
47168930dc | ||
|
|
3043093d22 | ||
|
|
271552b453 | ||
|
|
6de7bf3f20 | ||
|
|
ca1b05fff5 | ||
|
|
1d2497116d | ||
|
|
fb020f9f3c | ||
|
|
e344c3e6a4 | ||
|
|
e400966117 | ||
|
|
c98a16a2dd | ||
|
|
1a0d73ff8b | ||
|
|
163e6f0426 | ||
|
|
a2d0e93172 | ||
|
|
b2690ab2c5 | ||
|
|
c7772ca91e | ||
|
|
ffb117d85d | ||
|
|
45c7be3d50 | ||
|
|
544de57628 | ||
|
|
85618c8470 | ||
|
|
e7e91f4c50 | ||
|
|
e220921440 | ||
|
|
81cb44c5cf | ||
|
|
8302a934cc |
@@ -0,0 +1,18 @@
|
|||||||
|
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 echo 'export FLYCTL_INSTALL="/home/node/.fly"' >> ~/.bashrc
|
||||||
|
# RUN echo 'export PATH="$FLYCTL_INSTALL/bin:$PATH"' >> ~/.bashrc
|
||||||
|
|
||||||
|
RUN npm install -g bun
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
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
|
||||||
|
|
||||||
Vendored
+1
-8
@@ -1,14 +1,7 @@
|
|||||||
{
|
{
|
||||||
"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
|
||||||
"stripe.vscode-stripe", // stripe VSCode extension
|
"biomejs.biome" // improved i18n DX
|
||||||
"Prisma.prisma", // syntax|format|completion for prisma
|
|
||||||
"rebornix.project-snippets", // Share useful snippets between collaborators
|
|
||||||
"inlang.vs-code-extension" // improved i18n DX
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+5
-7
@@ -1,18 +1,16 @@
|
|||||||
{
|
{
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
"editor.formatOnSave": false,
|
"editor.formatOnSave": true,
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll.eslint": true
|
"quickfix.biome": "always"
|
||||||
|
// "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" }
|
||||||
// ],
|
// ],
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ Open source comfyui deployment platform, a `vercel` for generative workflow infr
|
|||||||
|
|
||||||
Join [Discord](https://discord.gg/EEYcQmdYZw) to chat more or visit [Comfy Deploy](https://comfydeploy.com/) to get started!
|
Join [Discord](https://discord.gg/EEYcQmdYZw) to chat more or visit [Comfy Deploy](https://comfydeploy.com/) to get started!
|
||||||
|
|
||||||
|
Check out our latest [nextjs starter kit](https://github.com/BennyKok/comfyui-deploy-next-example) with Comfy Deploy
|
||||||
|
|
||||||
\# How it works
|
\# How it works
|
||||||
|
|
||||||
1. Comfy Deploy Dashboard (https://comfydeploy.com) or self-hosted version
|
1. Comfy Deploy Dashboard (https://comfydeploy.com) or self-hosted version
|
||||||
@@ -73,10 +75,11 @@ Major areas
|
|||||||
3. `bun i`
|
3. `bun i`
|
||||||
4. Start docker
|
4. Start docker
|
||||||
5. `cp .env.example .env.local`
|
5. `cp .env.example .env.local`
|
||||||
6. Repace `JWT_SECRET` with `openssl rand -hex 32`
|
6. Replace `JWT_SECRET` with `openssl rand -hex 32`
|
||||||
7. Get a local clerk dev key for `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY`
|
7. Get a local clerk dev key for `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY`
|
||||||
8. Keep a terminal live for `bun run db-dev`
|
8. Keep a terminal live for `bun run db-dev`
|
||||||
9. Finally start the next server with `bun dev`
|
9. Execute the local migration to create the initial data `bun run migrate-local`
|
||||||
|
10. Finally start the next server with `bun dev`
|
||||||
|
|
||||||
**Schema Changes**
|
**Schema Changes**
|
||||||
|
|
||||||
@@ -132,4 +135,4 @@ SPACES_CDN_FORCE_PATH_STYLE="false"
|
|||||||
SPACES_REGION="nyc3"
|
SPACES_REGION="nyc3"
|
||||||
SPACES_CDN_DONT_INCLUDE_BUCKET="false"
|
SPACES_CDN_DONT_INCLUDE_BUCKET="false"
|
||||||
SPACES_CDN_FORCE_PATH_STYLE="true"
|
SPACES_CDN_FORCE_PATH_STYLE="true"
|
||||||
```
|
```
|
||||||
|
|||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"$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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -312,7 +312,8 @@ async def build_logic(item: Item):
|
|||||||
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,
|
||||||
|
"civitai_token": os.environ.get("CIVITAI_TOKEN", "")
|
||||||
}
|
}
|
||||||
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))
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ if not deploy_test:
|
|||||||
|
|
||||||
dockerfile_image = (
|
dockerfile_image = (
|
||||||
modal.Image.debian_slim()
|
modal.Image.debian_slim()
|
||||||
|
.env({
|
||||||
|
"CIVITAI_TOKEN": config["civitai_token"],
|
||||||
|
})
|
||||||
.apt_install("git", "wget")
|
.apt_install("git", "wget")
|
||||||
.pip_install(
|
.pip_install(
|
||||||
"git+https://github.com/modal-labs/asgiproxy.git", "httpx", "tqdm"
|
"git+https://github.com/modal-labs/asgiproxy.git", "httpx", "tqdm"
|
||||||
@@ -231,7 +234,8 @@ def run(input: Input):
|
|||||||
async def bar(request_input: RequestInput):
|
async def bar(request_input: RequestInput):
|
||||||
# print(request_input)
|
# print(request_input)
|
||||||
if not deploy_test:
|
if not deploy_test:
|
||||||
return run.remote(request_input.input)
|
run.spawn(request_input.input)
|
||||||
|
return {"status": "success"}
|
||||||
# pass
|
# pass
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,12 @@ with open('models.json') as f:
|
|||||||
models = json.load(f)
|
models = json.load(f)
|
||||||
|
|
||||||
for model in models:
|
for model in models:
|
||||||
|
import os
|
||||||
|
if "civitai.com/api" in model['url'] and not "token=" in model['url']:
|
||||||
|
if "?" in model['url']:
|
||||||
|
model['url'] += "&token=" + os.environ.get('CIVITAI_TOKEN', '')
|
||||||
|
else:
|
||||||
|
model['url'] += "?token=" + os.environ.get('CIVITAI_TOKEN', '')
|
||||||
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)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
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)"}
|
||||||
@@ -29,9 +29,7 @@ class ComfyUIDeployExternalText:
|
|||||||
CATEGORY = "text"
|
CATEGORY = "text"
|
||||||
|
|
||||||
def run(self, input_id, default_value=None):
|
def run(self, input_id, default_value=None):
|
||||||
if not input_id or len(input_id.strip()) == 0:
|
return [default_value]
|
||||||
return [default_value]
|
|
||||||
return [input_id]
|
|
||||||
|
|
||||||
|
|
||||||
NODE_CLASS_MAPPINGS = {"ComfyUIDeployExternalText": ComfyUIDeployExternalText}
|
NODE_CLASS_MAPPINGS = {"ComfyUIDeployExternalText": ComfyUIDeployExternalText}
|
||||||
|
|||||||
+234
-17
@@ -22,10 +22,14 @@ from logging.handlers import RotatingFileHandler
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
import threading
|
import threading
|
||||||
|
import hashlib
|
||||||
|
import aiohttp
|
||||||
|
|
||||||
api = None
|
api = None
|
||||||
api_task = None
|
api_task = None
|
||||||
prompt_metadata = {}
|
prompt_metadata = {}
|
||||||
|
cd_enable_log = os.environ.get('CD_ENABLE_LOG', 'false').lower() == 'true'
|
||||||
|
cd_enable_run_log = os.environ.get('CD_ENABLE_RUN_LOG', 'false').lower() == 'true'
|
||||||
|
|
||||||
def post_prompt(json_data):
|
def post_prompt(json_data):
|
||||||
prompt_server = server.PromptServer.instance
|
prompt_server = server.PromptServer.instance
|
||||||
@@ -97,6 +101,7 @@ async def comfy_deploy_run(request):
|
|||||||
prompt_metadata[prompt_id] = {
|
prompt_metadata[prompt_id] = {
|
||||||
'status_endpoint': data.get('status_endpoint'),
|
'status_endpoint': data.get('status_endpoint'),
|
||||||
'file_upload_endpoint': data.get('file_upload_endpoint'),
|
'file_upload_endpoint': data.get('file_upload_endpoint'),
|
||||||
|
'workflow_api': workflow_api
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -113,6 +118,8 @@ async def comfy_deploy_run(request):
|
|||||||
"stack_trace": stack_trace
|
"stack_trace": stack_trace
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
# When there are critical errors, the prompt is actually not run
|
||||||
|
await update_run(prompt_id, Status.FAILED)
|
||||||
return web.Response(status=500, reason=f"{error_type}: {e}, {stack_trace_short}")
|
return web.Response(status=500, reason=f"{error_type}: {e}, {stack_trace_short}")
|
||||||
|
|
||||||
status = 200
|
status = 200
|
||||||
@@ -141,6 +148,138 @@ async def comfy_deploy_run(request):
|
|||||||
|
|
||||||
sockets = dict()
|
sockets = dict()
|
||||||
|
|
||||||
|
def get_comfyui_path_from_file_path(file_path):
|
||||||
|
file_path_parts = file_path.split("\\")
|
||||||
|
|
||||||
|
if file_path_parts[0] == "input":
|
||||||
|
print("matching input")
|
||||||
|
file_path = os.path.join(folder_paths.get_directory_by_type("input"), *file_path_parts[1:])
|
||||||
|
elif file_path_parts[0] == "models":
|
||||||
|
print("matching models")
|
||||||
|
file_path = folder_paths.get_full_path(file_path_parts[1], os.path.join(*file_path_parts[2:]))
|
||||||
|
|
||||||
|
print(file_path)
|
||||||
|
|
||||||
|
return file_path
|
||||||
|
|
||||||
|
# Form ComfyUI Manager
|
||||||
|
def compute_sha256_checksum(filepath):
|
||||||
|
filepath = get_comfyui_path_from_file_path(filepath)
|
||||||
|
"""Compute the SHA256 checksum of a file, in chunks"""
|
||||||
|
sha256 = hashlib.sha256()
|
||||||
|
with open(filepath, 'rb') as f:
|
||||||
|
for chunk in iter(lambda: f.read(4096), b''):
|
||||||
|
sha256.update(chunk)
|
||||||
|
return sha256.hexdigest()
|
||||||
|
|
||||||
|
# This is start uploading the files to Comfy Deploy
|
||||||
|
@server.PromptServer.instance.routes.post('/comfyui-deploy/upload-file')
|
||||||
|
async def upload_file(request):
|
||||||
|
data = await request.json()
|
||||||
|
|
||||||
|
file_path = data.get("file_path")
|
||||||
|
|
||||||
|
print("Original file path", file_path)
|
||||||
|
|
||||||
|
file_path = get_comfyui_path_from_file_path(file_path)
|
||||||
|
|
||||||
|
# return web.json_response({
|
||||||
|
# "error": f"File not uploaded"
|
||||||
|
# }, status=500)
|
||||||
|
|
||||||
|
token = data.get("token")
|
||||||
|
get_url = data.get("url")
|
||||||
|
|
||||||
|
try:
|
||||||
|
base = folder_paths.base_path
|
||||||
|
file_path = os.path.join(base, file_path)
|
||||||
|
|
||||||
|
if os.path.exists(file_path):
|
||||||
|
file_size = os.path.getsize(file_path)
|
||||||
|
file_extension = os.path.splitext(file_path)[1]
|
||||||
|
|
||||||
|
if file_extension in ['.jpg', '.jpeg']:
|
||||||
|
file_type = 'image/jpeg'
|
||||||
|
elif file_extension == '.png':
|
||||||
|
file_type = 'image/png'
|
||||||
|
elif file_extension == '.webp':
|
||||||
|
file_type = 'image/webp'
|
||||||
|
else:
|
||||||
|
file_type = 'application/octet-stream' # Default to binary file type if unknown
|
||||||
|
else:
|
||||||
|
return web.json_response({
|
||||||
|
"error": f"File not found: {file_path}"
|
||||||
|
}, status=404)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return web.json_response({
|
||||||
|
"error": str(e)
|
||||||
|
}, status=500)
|
||||||
|
|
||||||
|
if get_url:
|
||||||
|
try:
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
headers = {'Authorization': f'Bearer {token}'}
|
||||||
|
params = {'file_size': file_size, 'type': file_type}
|
||||||
|
async with session.get(get_url, params=params, headers=headers) as response:
|
||||||
|
if response.status == 200:
|
||||||
|
content = await response.json()
|
||||||
|
upload_url = content["upload_url"]
|
||||||
|
|
||||||
|
with open(file_path, 'rb') as f:
|
||||||
|
headers = {
|
||||||
|
"Content-Type": file_type,
|
||||||
|
"x-amz-acl": "public-read",
|
||||||
|
"Content-Length": str(file_size)
|
||||||
|
}
|
||||||
|
async with session.put(upload_url, data=f, headers=headers) as upload_response:
|
||||||
|
if upload_response.status == 200:
|
||||||
|
return web.json_response({
|
||||||
|
"message": "File uploaded successfully",
|
||||||
|
"download_url": content["download_url"]
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return web.json_response({
|
||||||
|
"error": f"Failed to upload file to {upload_url}. Status code: {upload_response.status}"
|
||||||
|
}, status=upload_response.status)
|
||||||
|
else:
|
||||||
|
return web.json_response({
|
||||||
|
"error": f"Failed to fetch data from {get_url}. Status code: {response.status}"
|
||||||
|
}, status=response.status)
|
||||||
|
except Exception as e:
|
||||||
|
return web.json_response({
|
||||||
|
"error": f"An error occurred while fetching data from {get_url}: {str(e)}"
|
||||||
|
}, status=500)
|
||||||
|
|
||||||
|
return web.json_response({
|
||||||
|
"error": f"File not uploaded"
|
||||||
|
}, status=500)
|
||||||
|
|
||||||
|
|
||||||
|
@server.PromptServer.instance.routes.get('/comfyui-deploy/get-file-hash')
|
||||||
|
async def get_file_hash(request):
|
||||||
|
file_path = request.rel_url.query.get('file_path', '')
|
||||||
|
|
||||||
|
if file_path is None:
|
||||||
|
return web.json_response({
|
||||||
|
"error": "file_path is required"
|
||||||
|
}, status=400)
|
||||||
|
|
||||||
|
try:
|
||||||
|
base = folder_paths.base_path
|
||||||
|
file_path = os.path.join(base, file_path)
|
||||||
|
# print("file_path", file_path)
|
||||||
|
file_hash = compute_sha256_checksum(
|
||||||
|
file_path
|
||||||
|
)
|
||||||
|
return web.json_response({
|
||||||
|
"file_hash": file_hash
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
return web.json_response({
|
||||||
|
"error": str(e)
|
||||||
|
}, status=500)
|
||||||
|
|
||||||
@server.PromptServer.instance.routes.get('/comfyui-deploy/ws')
|
@server.PromptServer.instance.routes.get('/comfyui-deploy/ws')
|
||||||
async def websocket_handler(request):
|
async def websocket_handler(request):
|
||||||
ws = web.WebSocketResponse()
|
ws = web.WebSocketResponse()
|
||||||
@@ -157,7 +296,9 @@ async def websocket_handler(request):
|
|||||||
try:
|
try:
|
||||||
# Send initial state to the new client
|
# Send initial state to the new client
|
||||||
await send("status", { 'sid': sid }, sid)
|
await send("status", { 'sid': sid }, sid)
|
||||||
await send_first_time_log(sid)
|
|
||||||
|
if cd_enable_log:
|
||||||
|
await send_first_time_log(sid)
|
||||||
|
|
||||||
async for msg in ws:
|
async for msg in ws:
|
||||||
if msg.type == aiohttp.WSMsgType.ERROR:
|
if msg.type == aiohttp.WSMsgType.ERROR:
|
||||||
@@ -203,7 +344,10 @@ 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([send(event, data), self.send_json_original(event, data, sid)])
|
await asyncio.wait([
|
||||||
|
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)
|
||||||
@@ -214,6 +358,17 @@ async def send_json_override(self, event, data, sid=None):
|
|||||||
if not have_pending_upload(prompt_id):
|
if not have_pending_upload(prompt_id):
|
||||||
update_run(prompt_id, Status.SUCCESS)
|
update_run(prompt_id, Status.SUCCESS)
|
||||||
|
|
||||||
|
if event == 'executing' and data.get('node') is not None:
|
||||||
|
node = data.get('node')
|
||||||
|
|
||||||
|
if 'prompt_id' in prompt_metadata:
|
||||||
|
if 'last_updated_node' in prompt_metadata[prompt_id] and prompt_metadata[prompt_id]['last_updated_node'] == node:
|
||||||
|
return
|
||||||
|
prompt_metadata[prompt_id]['last_updated_node'] = node
|
||||||
|
class_type = prompt_metadata[prompt_id]['workflow_api'][node]['class_type']
|
||||||
|
print("updating run live status", class_type)
|
||||||
|
await update_run_live_status(prompt_id, "Executing " + class_type)
|
||||||
|
|
||||||
if event == 'execution_error':
|
if event == 'execution_error':
|
||||||
# Careful this might not be fully awaited.
|
# Careful this might not be fully awaited.
|
||||||
await update_run_with_output(prompt_id, data)
|
await update_run_with_output(prompt_id, data)
|
||||||
@@ -233,7 +388,26 @@ class Status(Enum):
|
|||||||
FAILED = "failed"
|
FAILED = "failed"
|
||||||
UPLOADING = "uploading"
|
UPLOADING = "uploading"
|
||||||
|
|
||||||
|
# Global variable to keep track of the last read line number
|
||||||
|
last_read_line_number = 0
|
||||||
|
|
||||||
|
async def update_run_live_status(prompt_id, live_status):
|
||||||
|
if prompt_id not in prompt_metadata:
|
||||||
|
return
|
||||||
|
|
||||||
|
status_endpoint = prompt_metadata[prompt_id]['status_endpoint']
|
||||||
|
body = {
|
||||||
|
"run_id": prompt_id,
|
||||||
|
"live_status": live_status,
|
||||||
|
}
|
||||||
|
# requests.post(status_endpoint, json=body)
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
await session.post(status_endpoint, json=body)
|
||||||
|
|
||||||
|
|
||||||
def update_run(prompt_id, status: Status):
|
def update_run(prompt_id, status: Status):
|
||||||
|
global last_read_line_number
|
||||||
|
|
||||||
if prompt_id not in prompt_metadata:
|
if prompt_id not in prompt_metadata:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -248,16 +422,50 @@ def update_run(prompt_id, status: Status):
|
|||||||
"run_id": prompt_id,
|
"run_id": prompt_id,
|
||||||
"status": status.value,
|
"status": status.value,
|
||||||
}
|
}
|
||||||
prompt_metadata[prompt_id]['status'] = status
|
|
||||||
print(f"Status: {status.value}")
|
print(f"Status: {status.value}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
requests.post(status_endpoint, json=body)
|
requests.post(status_endpoint, json=body)
|
||||||
|
|
||||||
|
if cd_enable_run_log and (status == Status.SUCCESS or status == Status.FAILED):
|
||||||
|
try:
|
||||||
|
with open(comfyui_file_path, 'r') as log_file:
|
||||||
|
# log_data = log_file.read()
|
||||||
|
# Move to the last read line
|
||||||
|
all_log_data = log_file.read() # Read all log data
|
||||||
|
print("All log data before skipping:", all_log_data) # Log all data before skipping
|
||||||
|
log_file.seek(0) # Reset file pointer to the beginning
|
||||||
|
|
||||||
|
for _ in range(last_read_line_number):
|
||||||
|
next(log_file)
|
||||||
|
log_data = log_file.read()
|
||||||
|
# Update the last read line number
|
||||||
|
last_read_line_number += log_data.count('\n')
|
||||||
|
print("last_read_line_number", last_read_line_number)
|
||||||
|
print("log_data", log_data)
|
||||||
|
print("log_data.count(n)", log_data.count('\n'))
|
||||||
|
|
||||||
|
body = {
|
||||||
|
"run_id": prompt_id,
|
||||||
|
"log_data": [
|
||||||
|
{
|
||||||
|
"logs": log_data,
|
||||||
|
# "timestamp": time.time(),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
requests.post(status_endpoint, json=body)
|
||||||
|
except Exception as log_error:
|
||||||
|
print(f"Error reading log file: {log_error}")
|
||||||
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_type = type(e).__name__
|
error_type = type(e).__name__
|
||||||
stack_trace = traceback.format_exc().strip()
|
stack_trace = traceback.format_exc().strip()
|
||||||
print(f"Error occurred while updating run: {e} {stack_trace}")
|
print(f"Error occurred while updating run: {e} {stack_trace}")
|
||||||
|
finally:
|
||||||
|
prompt_metadata[prompt_id]['status'] = status
|
||||||
|
|
||||||
|
|
||||||
async def upload_file(prompt_id, filename, subfolder=None, content_type="image/png", type="output"):
|
async def upload_file(prompt_id, filename, subfolder=None, content_type="image/png", type="output"):
|
||||||
"""
|
"""
|
||||||
@@ -307,7 +515,9 @@ async def upload_file(prompt_id, filename, subfolder=None, content_type="image/p
|
|||||||
"Content-Length": str(len(data)),
|
"Content-Length": str(len(data)),
|
||||||
}
|
}
|
||||||
response = requests.put(ok.get("url"), headers=headers, data=data)
|
response = requests.put(ok.get("url"), headers=headers, data=data)
|
||||||
print("upload file response", response.status_code)
|
async with aiohttp.ClientSession() as session:
|
||||||
|
async with session.put(ok.get("url"), headers=headers, data=data) as response:
|
||||||
|
print("upload file response", response.status)
|
||||||
|
|
||||||
def have_pending_upload(prompt_id):
|
def have_pending_upload(prompt_id):
|
||||||
if 'prompt_id' in prompt_metadata and 'uploading_nodes' in prompt_metadata[prompt_id] and len(prompt_metadata[prompt_id]['uploading_nodes']) > 0:
|
if 'prompt_id' in prompt_metadata and 'uploading_nodes' in prompt_metadata[prompt_id] and len(prompt_metadata[prompt_id]['uploading_nodes']) > 0:
|
||||||
@@ -384,20 +594,25 @@ async def update_file_status(prompt_id, data, uploading, have_error=False, node_
|
|||||||
"prompt_id": prompt_id,
|
"prompt_id": prompt_id,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
async def handle_upload(prompt_id, data, key, content_type_key, default_content_type):
|
||||||
|
items = data.get(key, [])
|
||||||
|
for item in items:
|
||||||
|
await upload_file(
|
||||||
|
prompt_id,
|
||||||
|
item.get("filename"),
|
||||||
|
subfolder=item.get("subfolder"),
|
||||||
|
type=item.get("type"),
|
||||||
|
content_type=item.get(content_type_key, default_content_type)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Upload files in the background
|
# Upload files in the background
|
||||||
async def upload_in_background(prompt_id, data, node_id=None, have_upload=True):
|
async def upload_in_background(prompt_id, data, node_id=None, have_upload=True):
|
||||||
try:
|
try:
|
||||||
images = data.get('images', [])
|
await handle_upload(prompt_id, data, 'images', "content_type", "image/png")
|
||||||
for image in images:
|
await handle_upload(prompt_id, data, 'files', "content_type", "image/png")
|
||||||
await upload_file(prompt_id, image.get("filename"), subfolder=image.get("subfolder"), type=image.get("type"), content_type=image.get("content_type", "image/png"))
|
# This will also be mp4
|
||||||
|
await handle_upload(prompt_id, data, 'gifs', "format", "image/gif")
|
||||||
files = data.get('files', [])
|
|
||||||
for file in files:
|
|
||||||
await upload_file(prompt_id, file.get("filename"), subfolder=file.get("subfolder"), type=file.get("type"), content_type=file.get("content_type", "image/png"))
|
|
||||||
|
|
||||||
gifs = data.get('gifs', [])
|
|
||||||
for gif in gifs:
|
|
||||||
await upload_file(prompt_id, gif.get("filename"), subfolder=gif.get("subfolder"), type=gif.get("type"), content_type=gif.get("format", "image/gif"))
|
|
||||||
|
|
||||||
if have_upload:
|
if have_upload:
|
||||||
await update_file_status(prompt_id, data, False, node_id=node_id)
|
await update_file_status(prompt_id, data, False, node_id=node_id)
|
||||||
@@ -438,6 +653,7 @@ prompt_server.send_json = send_json_override.__get__(prompt_server, server.Promp
|
|||||||
root_path = os.path.dirname(os.path.abspath(__file__))
|
root_path = os.path.dirname(os.path.abspath(__file__))
|
||||||
two_dirs_up = os.path.dirname(os.path.dirname(root_path))
|
two_dirs_up = os.path.dirname(os.path.dirname(root_path))
|
||||||
log_file_path = os.path.join(two_dirs_up, 'comfy-deploy.log')
|
log_file_path = os.path.join(two_dirs_up, 'comfy-deploy.log')
|
||||||
|
comfyui_file_path = os.path.join(two_dirs_up, 'comfyui.log')
|
||||||
|
|
||||||
last_read_line = 0
|
last_read_line = 0
|
||||||
|
|
||||||
@@ -477,4 +693,5 @@ def run_in_new_thread(coroutine):
|
|||||||
t.start()
|
t.start()
|
||||||
asyncio.run_coroutine_threadsafe(coroutine, new_loop)
|
asyncio.run_coroutine_threadsafe(coroutine, new_loop)
|
||||||
|
|
||||||
run_in_new_thread(watch_file_changes(log_file_path, send_logs_to_websocket))
|
if cd_enable_log:
|
||||||
|
run_in_new_thread(watch_file_changes(log_file_path, send_logs_to_websocket))
|
||||||
|
|||||||
+43
-32
@@ -7,45 +7,56 @@ import threading
|
|||||||
import logging
|
import logging
|
||||||
from logging.handlers import RotatingFileHandler
|
from logging.handlers import RotatingFileHandler
|
||||||
|
|
||||||
handler = RotatingFileHandler('comfy-deploy.log', maxBytes=500000, backupCount=5)
|
# Running with export CD_ENABLE_LOG=true; python main.py
|
||||||
|
|
||||||
original_stdout = sys.stdout
|
# Check for 'cd-enable-log' flag in input arguments
|
||||||
original_stderr = sys.stderr
|
# cd_enable_log = '--cd-enable-log' in sys.argv
|
||||||
|
cd_enable_log = os.environ.get('CD_ENABLE_LOG', 'false').lower() == 'true'
|
||||||
|
|
||||||
class StreamToLogger():
|
def setup():
|
||||||
def __init__(self, log_level):
|
handler = RotatingFileHandler('comfy-deploy.log', maxBytes=500000, backupCount=5)
|
||||||
self.log_level = log_level
|
|
||||||
|
|
||||||
def write(self, buf):
|
original_stdout = sys.stdout
|
||||||
if (self.log_level == logging.INFO):
|
original_stderr = sys.stderr
|
||||||
original_stdout.write(buf)
|
|
||||||
original_stdout.flush()
|
|
||||||
elif (self.log_level == logging.ERROR):
|
|
||||||
original_stderr.write(buf)
|
|
||||||
original_stderr.flush()
|
|
||||||
|
|
||||||
for line in buf.rstrip().splitlines():
|
class StreamToLogger():
|
||||||
handler.handle(
|
def __init__(self, log_level):
|
||||||
logging.LogRecord(
|
self.log_level = log_level
|
||||||
name="comfy-deploy",
|
|
||||||
level=self.log_level,
|
def write(self, buf):
|
||||||
pathname="prestartup_script.py",
|
if (self.log_level == logging.INFO):
|
||||||
lineno=1,
|
original_stdout.write(buf)
|
||||||
msg=line.rstrip(),
|
original_stdout.flush()
|
||||||
args=None,
|
elif (self.log_level == logging.ERROR):
|
||||||
exc_info=None
|
original_stderr.write(buf)
|
||||||
|
original_stderr.flush()
|
||||||
|
|
||||||
|
for line in buf.rstrip().splitlines():
|
||||||
|
handler.handle(
|
||||||
|
logging.LogRecord(
|
||||||
|
name="comfy-deploy",
|
||||||
|
level=self.log_level,
|
||||||
|
pathname="prestartup_script.py",
|
||||||
|
lineno=1,
|
||||||
|
msg=line.rstrip(),
|
||||||
|
args=None,
|
||||||
|
exc_info=None
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
if (self.log_level == logging.INFO):
|
if (self.log_level == logging.INFO):
|
||||||
original_stdout.flush()
|
original_stdout.flush()
|
||||||
elif (self.log_level == logging.ERROR):
|
elif (self.log_level == logging.ERROR):
|
||||||
original_stderr.flush()
|
original_stderr.flush()
|
||||||
|
|
||||||
# Redirect stdout and stderr to the logger
|
# Redirect stdout and stderr to the logger
|
||||||
sys.stdout = StreamToLogger(logging.INFO)
|
sys.stdout = StreamToLogger(logging.INFO)
|
||||||
sys.stderr = StreamToLogger(logging.ERROR)
|
sys.stderr = StreamToLogger(logging.ERROR)
|
||||||
|
|
||||||
|
if cd_enable_log:
|
||||||
|
print("** Comfy Deploy logging enabled")
|
||||||
|
setup()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Get the absolute path of the script's directory
|
# Get the absolute path of the script's directory
|
||||||
|
|||||||
+429
-49
@@ -1,6 +1,7 @@
|
|||||||
import { app } from "./app.js";
|
import { app } from "./app.js";
|
||||||
import { api } from "./api.js";
|
import { api } from "./api.js";
|
||||||
import { ComfyWidgets, LGraphNode } from "./widgets.js";
|
import { ComfyWidgets, LGraphNode } from "./widgets.js";
|
||||||
|
import { generateDependencyGraph } from "https://esm.sh/[email protected]";
|
||||||
|
|
||||||
/** @typedef {import('../../../web/types/comfy.js').ComfyExtension} ComfyExtension*/
|
/** @typedef {import('../../../web/types/comfy.js').ComfyExtension} ComfyExtension*/
|
||||||
/** @type {ComfyExtension} */
|
/** @type {ComfyExtension} */
|
||||||
@@ -9,6 +10,76 @@ 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, workflow_id, error } = data;
|
||||||
|
if (error) {
|
||||||
|
infoDialog.showMessage("Unable to load this workflow", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adding a delay to wait for the intial graph to load
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||||
|
|
||||||
|
workflow?.nodes.forEach((x) => {
|
||||||
|
if (x?.type === "ComfyDeploy") {
|
||||||
|
x.widgets_values[1] = workflow_id;
|
||||||
|
// x.widgets_values[2] = workflow_version.version;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/** @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() {
|
||||||
@@ -108,6 +179,92 @@ function showError(title, message) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createDynamicUIHtml(data) {
|
||||||
|
console.log(data);
|
||||||
|
let html =
|
||||||
|
'<div style="max-width: 1024px; margin: 14px auto; display: flex; flex-direction: column; gap: 24px;">';
|
||||||
|
const bgcolor = "var(--comfy-input-bg)";
|
||||||
|
const evenBg = "var(--border-color)";
|
||||||
|
const textColor = "var(--input-text)";
|
||||||
|
|
||||||
|
// Custom Nodes
|
||||||
|
html += `<div style="background-color: ${bgcolor}; padding: 24px; border-radius: 8px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);">`;
|
||||||
|
html +=
|
||||||
|
'<h2 style="margin-top: 0px; font-size: 24px; font-weight: bold; margin-bottom: 16px;">Custom Nodes</h2>';
|
||||||
|
|
||||||
|
if (data.missing_nodes?.length > 0) {
|
||||||
|
html += `
|
||||||
|
<div style="border-bottom: 1px solid #e2e8f0; padding: 4px 12px; background-color: ${evenBg}">
|
||||||
|
<h3 style="font-size: 14px; font-weight: semibold; margin-bottom: 8px;">Missing Nodes</h3>
|
||||||
|
<p style="font-size: 12px;">These nodes are not found with any matching custom_nodes in the ComfyUI Manager Database</p>
|
||||||
|
${data.missing_nodes
|
||||||
|
.map((node) => {
|
||||||
|
return `<p style="font-size: 14px; color: #d69e2e;">${node}</p>`;
|
||||||
|
})
|
||||||
|
.join("")}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.values(data.custom_nodes).forEach((node) => {
|
||||||
|
html += `
|
||||||
|
<div style="border-bottom: 1px solid #e2e8f0; padding-top: 16px;">
|
||||||
|
<a href="${
|
||||||
|
node.url
|
||||||
|
}" target="_blank" style="font-size: 18px; font-weight: semibold; color: white; text-decoration: none;">${
|
||||||
|
node.name
|
||||||
|
}</a>
|
||||||
|
<p style="font-size: 14px; color: #4b5563;">${node.hash}</p>
|
||||||
|
${
|
||||||
|
node.warning
|
||||||
|
? `<p style="font-size: 14px; color: #d69e2e;">${node.warning}</p>`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
html += "</div>";
|
||||||
|
|
||||||
|
// Models
|
||||||
|
html += `<div style="background-color: ${bgcolor}; padding: 24px; border-radius: 8px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);">`;
|
||||||
|
html +=
|
||||||
|
'<h2 style="margin-top: 0px; font-size: 24px; font-weight: bold; margin-bottom: 16px;">Models</h2>';
|
||||||
|
|
||||||
|
Object.entries(data.models).forEach(([section, items]) => {
|
||||||
|
html += `
|
||||||
|
<div style="border-bottom: 1px solid #e2e8f0; padding-top: 8px; padding-bottom: 8px;">
|
||||||
|
<h3 style="font-size: 18px; font-weight: semibold; margin-bottom: 8px;">${
|
||||||
|
section.charAt(0).toUpperCase() + section.slice(1)
|
||||||
|
}</h3>`;
|
||||||
|
items.forEach((item) => {
|
||||||
|
html += `<p style="font-size: 14px; color: ${textColor};">${item.name}</p>`;
|
||||||
|
});
|
||||||
|
html += "</div>";
|
||||||
|
});
|
||||||
|
html += "</div>";
|
||||||
|
|
||||||
|
// Models
|
||||||
|
html += `<div style="background-color: ${bgcolor}; padding: 24px; border-radius: 8px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);">`;
|
||||||
|
html +=
|
||||||
|
'<h2 style="margin-top: 0px; font-size: 24px; font-weight: bold; margin-bottom: 16px;">Files</h2>';
|
||||||
|
|
||||||
|
Object.entries(data.files).forEach(([section, items]) => {
|
||||||
|
html += `
|
||||||
|
<div style="border-bottom: 1px solid #e2e8f0; padding-top: 8px; padding-bottom: 8px;">
|
||||||
|
<h3 style="font-size: 18px; font-weight: semibold; margin-bottom: 8px;">${
|
||||||
|
section.charAt(0).toUpperCase() + section.slice(1)
|
||||||
|
}</h3>`;
|
||||||
|
items.forEach((item) => {
|
||||||
|
html += `<p style="font-size: 14px; color: ${textColor};">${item.name}</p>`;
|
||||||
|
});
|
||||||
|
html += "</div>";
|
||||||
|
});
|
||||||
|
html += "</div>";
|
||||||
|
|
||||||
|
html += "</div>";
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
function addButton() {
|
function addButton() {
|
||||||
const menu = document.querySelector(".comfy-menu");
|
const menu = document.querySelector(".comfy-menu");
|
||||||
|
|
||||||
@@ -119,8 +276,29 @@ function addButton() {
|
|||||||
/** @type {LGraph} */
|
/** @type {LGraph} */
|
||||||
const graph = app.graph;
|
const graph = app.graph;
|
||||||
|
|
||||||
|
let { endpoint, apiKey, displayName } = getData();
|
||||||
|
|
||||||
|
if (!endpoint || !apiKey || apiKey === "" || endpoint === "") {
|
||||||
|
configDialog.show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ok = await confirmDialog.confirm(
|
||||||
|
"Confirm deployment -> " + displayName,
|
||||||
|
`A new version will be deployed, are you conform? <br><br><input id="include-deps" type="checkbox" checked>Include dependence</input>`,
|
||||||
|
);
|
||||||
|
if (!ok) return;
|
||||||
|
|
||||||
|
const includeDeps = document.getElementById("include-deps").checked;
|
||||||
|
|
||||||
|
if (endpoint.endsWith("/")) {
|
||||||
|
endpoint = endpoint.slice(0, -1);
|
||||||
|
}
|
||||||
|
loadingDialog.showLoading("Generating snapshot", "Please wait...");
|
||||||
|
|
||||||
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);
|
||||||
|
loadingDialog.close();
|
||||||
|
|
||||||
if (!snapshot) {
|
if (!snapshot) {
|
||||||
showError(
|
showError(
|
||||||
@@ -154,52 +332,122 @@ function addButton() {
|
|||||||
|
|
||||||
const deployMetaNode = deployMeta[0];
|
const deployMetaNode = deployMeta[0];
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
console.log(workflow_name, workflow_id);
|
|
||||||
|
|
||||||
const prompt = await app.graphToPrompt();
|
const prompt = await app.graphToPrompt();
|
||||||
console.log(graph);
|
let deps = undefined;
|
||||||
console.log(prompt);
|
|
||||||
|
|
||||||
// const endpoint = localStorage.getItem("endpoint") ?? "";
|
if (includeDeps) {
|
||||||
// const apiKey = localStorage.getItem("apiKey");
|
loadingDialog.showLoading("Fetching existing version", "Please wait...");
|
||||||
|
|
||||||
const { endpoint, apiKey } = getData();
|
const existing_workflow = await fetch(
|
||||||
|
endpoint + "/api/workflow/" + workflow_id,
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: "Bearer " + apiKey,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.then((x) => x.json())
|
||||||
|
.catch(() => {
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
|
||||||
if (!endpoint || !apiKey || apiKey === "" || endpoint === "") {
|
loadingDialog.close();
|
||||||
configDialog.show();
|
|
||||||
return;
|
loadingDialog.showLoading(
|
||||||
|
"Generating dependency graph",
|
||||||
|
"Please wait...",
|
||||||
|
);
|
||||||
|
deps = await generateDependencyGraph({
|
||||||
|
workflow_api: prompt.output,
|
||||||
|
snapshot: snapshot,
|
||||||
|
computeFileHash: async (file) => {
|
||||||
|
console.log(file);
|
||||||
|
loadingDialog.showLoading("Generating hash", file);
|
||||||
|
const hash = await fetch(
|
||||||
|
`/comfyui-deploy/get-file-hash?file_path=${encodeURIComponent(
|
||||||
|
file,
|
||||||
|
)}`,
|
||||||
|
).then((x) => x.json());
|
||||||
|
loadingDialog.showLoading("Generating hash", file);
|
||||||
|
console.log(hash);
|
||||||
|
return hash.file_hash;
|
||||||
|
},
|
||||||
|
handleFileUpload: async (file, hash, prevhash) => {
|
||||||
|
console.log("Uploading ", file);
|
||||||
|
loadingDialog.showLoading("Uploading file", file);
|
||||||
|
try {
|
||||||
|
const { download_url } = await fetch(
|
||||||
|
`/comfyui-deploy/upload-file`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({
|
||||||
|
file_path: file,
|
||||||
|
token: apiKey,
|
||||||
|
url: endpoint + "/api/upload-url",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.then((x) => x.json())
|
||||||
|
.catch(() => {
|
||||||
|
loadingDialog.close();
|
||||||
|
confirmDialog.confirm("Error", "Unable to upload file " + file);
|
||||||
|
});
|
||||||
|
loadingDialog.showLoading("Uploaded file", file);
|
||||||
|
console.log(download_url);
|
||||||
|
return download_url;
|
||||||
|
} catch (error) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
existingDependencies: existing_workflow.dependencies,
|
||||||
|
});
|
||||||
|
|
||||||
|
loadingDialog.close();
|
||||||
|
|
||||||
|
const depsOk = await confirmDialog.confirm(
|
||||||
|
"Check dependencies",
|
||||||
|
// JSON.stringify(deps, null, 2),
|
||||||
|
createDynamicUIHtml(deps),
|
||||||
|
);
|
||||||
|
if (!depsOk) return;
|
||||||
|
|
||||||
|
console.log(deps);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ok = await confirmDialog.confirm("Confirm deployment", "A new version will be deployed, are you conform?")
|
loadingDialog.showLoading("Deploying...");
|
||||||
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/upload";
|
// console.log(prompt.workflow);
|
||||||
|
|
||||||
|
const apiRoute = endpoint + "/api/workflow";
|
||||||
// const userId = apiKey
|
// const userId = apiKey
|
||||||
try {
|
try {
|
||||||
|
const body = {
|
||||||
|
workflow_name,
|
||||||
|
workflow_id,
|
||||||
|
workflow: prompt.workflow,
|
||||||
|
workflow_api: prompt.output,
|
||||||
|
snapshot: snapshot,
|
||||||
|
dependencies: deps,
|
||||||
|
};
|
||||||
|
console.log(body);
|
||||||
let data = await fetch(apiRoute, {
|
let data = await fetch(apiRoute, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify(body),
|
||||||
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,
|
||||||
@@ -214,6 +462,8 @@ function addButton() {
|
|||||||
data = await data.json();
|
data = await data.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadingDialog.close();
|
||||||
|
|
||||||
title.textContent = "Done";
|
title.textContent = "Done";
|
||||||
title.style.color = "green";
|
title.style.color = "green";
|
||||||
|
|
||||||
@@ -230,6 +480,7 @@ function addButton() {
|
|||||||
title.style.color = "white";
|
title.style.color = "white";
|
||||||
}, 1000);
|
}, 1000);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
loadingDialog.close();
|
||||||
app.ui.dialog.show(e);
|
app.ui.dialog.show(e);
|
||||||
console.error(e);
|
console.error(e);
|
||||||
title.textContent = "Error";
|
title.textContent = "Error";
|
||||||
@@ -275,14 +526,16 @@ 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() {
|
||||||
return [
|
this.button = $el("button", {
|
||||||
$el("button", {
|
type: "button",
|
||||||
type: "button",
|
textContent: "Close",
|
||||||
textContent: "Close",
|
onclick: () => this.close(),
|
||||||
onclick: () => this.close(),
|
});
|
||||||
}),
|
return [this.button];
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
@@ -301,6 +554,72 @@ 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: 100%; max-width: 600px; 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: 12px;">${title} ${
|
||||||
|
this.loadingIcon
|
||||||
|
}</h3>
|
||||||
|
${message ? `<label>${message}</label>` : ""}
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InputDialog extends InfoDialog {
|
export class InputDialog extends InfoDialog {
|
||||||
@@ -367,7 +686,6 @@ export class InputDialog extends InfoDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class ConfirmDialog extends InfoDialog {
|
export class ConfirmDialog extends InfoDialog {
|
||||||
callback = undefined;
|
callback = undefined;
|
||||||
|
|
||||||
@@ -417,7 +735,7 @@ export class ConfirmDialog extends InfoDialog {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.callback = resolve;
|
this.callback = resolve;
|
||||||
this.show(`
|
this.show(`
|
||||||
<div style="width: 400px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
|
<div style="width: 100%; max-width: 600px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
|
||||||
<h3 style="margin: 0px;">${title}</h3>
|
<h3 style="margin: 0px;">${title}</h3>
|
||||||
<label>
|
<label>
|
||||||
${message}
|
${message}
|
||||||
@@ -429,9 +747,15 @@ 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";
|
||||||
@@ -454,8 +778,21 @@ 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();
|
||||||
@@ -498,22 +835,24 @@ export class ConfigDialog extends ComfyDialog {
|
|||||||
|
|
||||||
close() {
|
close() {
|
||||||
this.element.style.display = "none";
|
this.element.style.display = "none";
|
||||||
|
clearInterval(this.poll);
|
||||||
|
clearTimeout(this.timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
save(api_key, displayName) {
|
||||||
|
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 = this.container.querySelector("#apiKey").value;
|
const apiKey = api_key ?? this.container.querySelector("#apiKey").value;
|
||||||
const data = {
|
saveData({
|
||||||
endpoint,
|
endpoint,
|
||||||
apiKey,
|
apiKey,
|
||||||
};
|
displayName,
|
||||||
localStorage.setItem(
|
environment: deployOption,
|
||||||
"comfy_deploy_env_data_" + deployOption,
|
});
|
||||||
JSON.stringify(data),
|
|
||||||
);
|
|
||||||
this.close();
|
this.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,12 +866,8 @@ 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" ${
|
<option value="cloud" ${data.environment === "cloud" ? "selected" : ""}>Cloud</option>
|
||||||
data.environment === "cloud" ? "selected" : ""
|
<option value="local" ${data.environment === "local" ? "selected" : ""}>Local</option>
|
||||||
}>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%;">
|
||||||
@@ -542,16 +877,61 @@ export class ConfigDialog extends ComfyDialog {
|
|||||||
}">
|
}">
|
||||||
</label>
|
</label>
|
||||||
<label style="color: white;">
|
<label style="color: white;">
|
||||||
API Key:
|
API Key: ${data.displayName ?? ""}
|
||||||
<input id="apiKey" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;" type="password" value="${
|
<input id="apiKey" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;" type="password" value="${
|
||||||
data.apiKey
|
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", function (e) {
|
apiKeyInput.addEventListener("paste", (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -16,4 +16,7 @@ SPACES_CDN_FORCE_PATH_STYLE="true"
|
|||||||
MODAL_BUILDER_URL=
|
MODAL_BUILDER_URL=
|
||||||
|
|
||||||
JWT_SECRET="openssl rand -hex 32"
|
JWT_SECRET="openssl rand -hex 32"
|
||||||
PLAUSIBLE_DOMAIN=
|
PLAUSIBLE_DOMAIN=
|
||||||
|
|
||||||
|
NEXT_PUBLIC_POSTHOG_KEY="your-api-key"
|
||||||
|
NEXT_PUBLIC_POSTHOG_HOST="your-ph-address"
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
node_modules
|
|
||||||
**/node_modules
|
|
||||||
**/.next
|
|
||||||
**/public
|
|
||||||
packages/prisma/zod
|
|
||||||
apps/web/public/embed
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
/** @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",
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
ALTER TYPE "workflow_run_origin" ADD VALUE 'public-share';
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE "comfyui_deploy"."deployments" ADD COLUMN "description" text;--> statement-breakpoint
|
||||||
|
ALTER TABLE "comfyui_deploy"."deployments" ADD COLUMN "showcase_media" jsonb;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "comfyui_deploy"."deployments" ADD COLUMN "org_id" text;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "started_at" timestamp;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
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");
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
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
|
||||||
|
);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "comfyui_deploy"."auth_requests" ADD COLUMN "expired_date" timestamp;
|
||||||
@@ -0,0 +1,738 @@
|
|||||||
|
{
|
||||||
|
"id": "7bdeb193-ee27-40cc-8252-59ddaf505ab8",
|
||||||
|
"prevId": "dddfedc3-5b2f-4d54-a996-821945b9ff80",
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "pg",
|
||||||
|
"tables": {
|
||||||
|
"api_keys": {
|
||||||
|
"name": "api_keys",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"name": "key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"org_id": {
|
||||||
|
"name": "org_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"revoked": {
|
||||||
|
"name": "revoked",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"api_keys_user_id_users_id_fk": {
|
||||||
|
"name": "api_keys_user_id_users_id_fk",
|
||||||
|
"tableFrom": "api_keys",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"api_keys_key_unique": {
|
||||||
|
"name": "api_keys_key_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"key"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deployments": {
|
||||||
|
"name": "deployments",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"workflow_version_id": {
|
||||||
|
"name": "workflow_version_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"workflow_id": {
|
||||||
|
"name": "workflow_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"machine_id": {
|
||||||
|
"name": "machine_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"environment": {
|
||||||
|
"name": "environment",
|
||||||
|
"type": "deployment_environment",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"deployments_user_id_users_id_fk": {
|
||||||
|
"name": "deployments_user_id_users_id_fk",
|
||||||
|
"tableFrom": "deployments",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"deployments_workflow_version_id_workflow_versions_id_fk": {
|
||||||
|
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
|
||||||
|
"tableFrom": "deployments",
|
||||||
|
"tableTo": "workflow_versions",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workflow_version_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"deployments_workflow_id_workflows_id_fk": {
|
||||||
|
"name": "deployments_workflow_id_workflows_id_fk",
|
||||||
|
"tableFrom": "deployments",
|
||||||
|
"tableTo": "workflows",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workflow_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"deployments_machine_id_machines_id_fk": {
|
||||||
|
"name": "deployments_machine_id_machines_id_fk",
|
||||||
|
"tableFrom": "deployments",
|
||||||
|
"tableTo": "machines",
|
||||||
|
"columnsFrom": [
|
||||||
|
"machine_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"machines": {
|
||||||
|
"name": "machines",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"org_id": {
|
||||||
|
"name": "org_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"endpoint": {
|
||||||
|
"name": "endpoint",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"name": "disabled",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"auth_token": {
|
||||||
|
"name": "auth_token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"name": "type",
|
||||||
|
"type": "machine_type",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'classic'"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"type": "machine_status",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'ready'"
|
||||||
|
},
|
||||||
|
"snapshot": {
|
||||||
|
"name": "snapshot",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"models": {
|
||||||
|
"name": "models",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"gpu": {
|
||||||
|
"name": "gpu",
|
||||||
|
"type": "machine_gpu",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"build_machine_instance_id": {
|
||||||
|
"name": "build_machine_instance_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"build_log": {
|
||||||
|
"name": "build_log",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"machines_user_id_users_id_fk": {
|
||||||
|
"name": "machines_user_id_users_id_fk",
|
||||||
|
"tableFrom": "machines",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"name": "users",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"name": "username",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"workflow_run_outputs": {
|
||||||
|
"name": "workflow_run_outputs",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"run_id": {
|
||||||
|
"name": "run_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"name": "data",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"workflow_run_outputs_run_id_workflow_runs_id_fk": {
|
||||||
|
"name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
|
||||||
|
"tableFrom": "workflow_run_outputs",
|
||||||
|
"tableTo": "workflow_runs",
|
||||||
|
"columnsFrom": [
|
||||||
|
"run_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"workflow_runs": {
|
||||||
|
"name": "workflow_runs",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"workflow_version_id": {
|
||||||
|
"name": "workflow_version_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"workflow_inputs": {
|
||||||
|
"name": "workflow_inputs",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"workflow_id": {
|
||||||
|
"name": "workflow_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"machine_id": {
|
||||||
|
"name": "machine_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"origin": {
|
||||||
|
"name": "origin",
|
||||||
|
"type": "workflow_run_origin",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'api'"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"type": "workflow_run_status",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'not-started'"
|
||||||
|
},
|
||||||
|
"ended_at": {
|
||||||
|
"name": "ended_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
|
||||||
|
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
|
||||||
|
"tableFrom": "workflow_runs",
|
||||||
|
"tableTo": "workflow_versions",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workflow_version_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "set null",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"workflow_runs_workflow_id_workflows_id_fk": {
|
||||||
|
"name": "workflow_runs_workflow_id_workflows_id_fk",
|
||||||
|
"tableFrom": "workflow_runs",
|
||||||
|
"tableTo": "workflows",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workflow_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"workflow_runs_machine_id_machines_id_fk": {
|
||||||
|
"name": "workflow_runs_machine_id_machines_id_fk",
|
||||||
|
"tableFrom": "workflow_runs",
|
||||||
|
"tableTo": "machines",
|
||||||
|
"columnsFrom": [
|
||||||
|
"machine_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "set null",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"workflows": {
|
||||||
|
"name": "workflows",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"org_id": {
|
||||||
|
"name": "org_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"workflows_user_id_users_id_fk": {
|
||||||
|
"name": "workflows_user_id_users_id_fk",
|
||||||
|
"tableFrom": "workflows",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"workflow_versions": {
|
||||||
|
"name": "workflow_versions",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"workflow_id": {
|
||||||
|
"name": "workflow_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"workflow": {
|
||||||
|
"name": "workflow",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"workflow_api": {
|
||||||
|
"name": "workflow_api",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"name": "version",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"snapshot": {
|
||||||
|
"name": "snapshot",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"workflow_versions_workflow_id_workflows_id_fk": {
|
||||||
|
"name": "workflow_versions_workflow_id_workflows_id_fk",
|
||||||
|
"tableFrom": "workflow_versions",
|
||||||
|
"tableTo": "workflows",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workflow_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {
|
||||||
|
"deployment_environment": {
|
||||||
|
"name": "deployment_environment",
|
||||||
|
"values": {
|
||||||
|
"staging": "staging",
|
||||||
|
"production": "production",
|
||||||
|
"public-share": "public-share"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"machine_gpu": {
|
||||||
|
"name": "machine_gpu",
|
||||||
|
"values": {
|
||||||
|
"T4": "T4",
|
||||||
|
"A10G": "A10G",
|
||||||
|
"A100": "A100"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"machine_status": {
|
||||||
|
"name": "machine_status",
|
||||||
|
"values": {
|
||||||
|
"ready": "ready",
|
||||||
|
"building": "building",
|
||||||
|
"error": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"machine_type": {
|
||||||
|
"name": "machine_type",
|
||||||
|
"values": {
|
||||||
|
"classic": "classic",
|
||||||
|
"runpod-serverless": "runpod-serverless",
|
||||||
|
"modal-serverless": "modal-serverless",
|
||||||
|
"comfy-deploy-serverless": "comfy-deploy-serverless"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"workflow_run_origin": {
|
||||||
|
"name": "workflow_run_origin",
|
||||||
|
"values": {
|
||||||
|
"manual": "manual",
|
||||||
|
"api": "api",
|
||||||
|
"public-share": "public-share"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"workflow_run_status": {
|
||||||
|
"name": "workflow_run_status",
|
||||||
|
"values": {
|
||||||
|
"not-started": "not-started",
|
||||||
|
"running": "running",
|
||||||
|
"uploading": "uploading",
|
||||||
|
"success": "success",
|
||||||
|
"failed": "failed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schemas": {
|
||||||
|
"comfyui_deploy": "comfyui_deploy"
|
||||||
|
},
|
||||||
|
"_meta": {
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {},
|
||||||
|
"columns": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,750 @@
|
|||||||
|
{
|
||||||
|
"id": "a7d6a8dd-0e15-4165-98a2-de2a334455dc",
|
||||||
|
"prevId": "7bdeb193-ee27-40cc-8252-59ddaf505ab8",
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "pg",
|
||||||
|
"tables": {
|
||||||
|
"api_keys": {
|
||||||
|
"name": "api_keys",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"name": "key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"org_id": {
|
||||||
|
"name": "org_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"revoked": {
|
||||||
|
"name": "revoked",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"api_keys_user_id_users_id_fk": {
|
||||||
|
"name": "api_keys_user_id_users_id_fk",
|
||||||
|
"tableFrom": "api_keys",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"api_keys_key_unique": {
|
||||||
|
"name": "api_keys_key_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"key"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deployments": {
|
||||||
|
"name": "deployments",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"workflow_version_id": {
|
||||||
|
"name": "workflow_version_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"workflow_id": {
|
||||||
|
"name": "workflow_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"machine_id": {
|
||||||
|
"name": "machine_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"name": "description",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"showcase_media": {
|
||||||
|
"name": "showcase_media",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"environment": {
|
||||||
|
"name": "environment",
|
||||||
|
"type": "deployment_environment",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"deployments_user_id_users_id_fk": {
|
||||||
|
"name": "deployments_user_id_users_id_fk",
|
||||||
|
"tableFrom": "deployments",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"deployments_workflow_version_id_workflow_versions_id_fk": {
|
||||||
|
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
|
||||||
|
"tableFrom": "deployments",
|
||||||
|
"tableTo": "workflow_versions",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workflow_version_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"deployments_workflow_id_workflows_id_fk": {
|
||||||
|
"name": "deployments_workflow_id_workflows_id_fk",
|
||||||
|
"tableFrom": "deployments",
|
||||||
|
"tableTo": "workflows",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workflow_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"deployments_machine_id_machines_id_fk": {
|
||||||
|
"name": "deployments_machine_id_machines_id_fk",
|
||||||
|
"tableFrom": "deployments",
|
||||||
|
"tableTo": "machines",
|
||||||
|
"columnsFrom": [
|
||||||
|
"machine_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"machines": {
|
||||||
|
"name": "machines",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"org_id": {
|
||||||
|
"name": "org_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"endpoint": {
|
||||||
|
"name": "endpoint",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"name": "disabled",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"auth_token": {
|
||||||
|
"name": "auth_token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"name": "type",
|
||||||
|
"type": "machine_type",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'classic'"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"type": "machine_status",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'ready'"
|
||||||
|
},
|
||||||
|
"snapshot": {
|
||||||
|
"name": "snapshot",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"models": {
|
||||||
|
"name": "models",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"gpu": {
|
||||||
|
"name": "gpu",
|
||||||
|
"type": "machine_gpu",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"build_machine_instance_id": {
|
||||||
|
"name": "build_machine_instance_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"build_log": {
|
||||||
|
"name": "build_log",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"machines_user_id_users_id_fk": {
|
||||||
|
"name": "machines_user_id_users_id_fk",
|
||||||
|
"tableFrom": "machines",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"name": "users",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"name": "username",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"workflow_run_outputs": {
|
||||||
|
"name": "workflow_run_outputs",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"run_id": {
|
||||||
|
"name": "run_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"name": "data",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"workflow_run_outputs_run_id_workflow_runs_id_fk": {
|
||||||
|
"name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
|
||||||
|
"tableFrom": "workflow_run_outputs",
|
||||||
|
"tableTo": "workflow_runs",
|
||||||
|
"columnsFrom": [
|
||||||
|
"run_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"workflow_runs": {
|
||||||
|
"name": "workflow_runs",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"workflow_version_id": {
|
||||||
|
"name": "workflow_version_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"workflow_inputs": {
|
||||||
|
"name": "workflow_inputs",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"workflow_id": {
|
||||||
|
"name": "workflow_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"machine_id": {
|
||||||
|
"name": "machine_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"origin": {
|
||||||
|
"name": "origin",
|
||||||
|
"type": "workflow_run_origin",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'api'"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"type": "workflow_run_status",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'not-started'"
|
||||||
|
},
|
||||||
|
"ended_at": {
|
||||||
|
"name": "ended_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
|
||||||
|
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
|
||||||
|
"tableFrom": "workflow_runs",
|
||||||
|
"tableTo": "workflow_versions",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workflow_version_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "set null",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"workflow_runs_workflow_id_workflows_id_fk": {
|
||||||
|
"name": "workflow_runs_workflow_id_workflows_id_fk",
|
||||||
|
"tableFrom": "workflow_runs",
|
||||||
|
"tableTo": "workflows",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workflow_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"workflow_runs_machine_id_machines_id_fk": {
|
||||||
|
"name": "workflow_runs_machine_id_machines_id_fk",
|
||||||
|
"tableFrom": "workflow_runs",
|
||||||
|
"tableTo": "machines",
|
||||||
|
"columnsFrom": [
|
||||||
|
"machine_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "set null",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"workflows": {
|
||||||
|
"name": "workflows",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"org_id": {
|
||||||
|
"name": "org_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"workflows_user_id_users_id_fk": {
|
||||||
|
"name": "workflows_user_id_users_id_fk",
|
||||||
|
"tableFrom": "workflows",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"workflow_versions": {
|
||||||
|
"name": "workflow_versions",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"workflow_id": {
|
||||||
|
"name": "workflow_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"workflow": {
|
||||||
|
"name": "workflow",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"workflow_api": {
|
||||||
|
"name": "workflow_api",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"name": "version",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"snapshot": {
|
||||||
|
"name": "snapshot",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"workflow_versions_workflow_id_workflows_id_fk": {
|
||||||
|
"name": "workflow_versions_workflow_id_workflows_id_fk",
|
||||||
|
"tableFrom": "workflow_versions",
|
||||||
|
"tableTo": "workflows",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workflow_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {
|
||||||
|
"deployment_environment": {
|
||||||
|
"name": "deployment_environment",
|
||||||
|
"values": {
|
||||||
|
"staging": "staging",
|
||||||
|
"production": "production",
|
||||||
|
"public-share": "public-share"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"machine_gpu": {
|
||||||
|
"name": "machine_gpu",
|
||||||
|
"values": {
|
||||||
|
"T4": "T4",
|
||||||
|
"A10G": "A10G",
|
||||||
|
"A100": "A100"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"machine_status": {
|
||||||
|
"name": "machine_status",
|
||||||
|
"values": {
|
||||||
|
"ready": "ready",
|
||||||
|
"building": "building",
|
||||||
|
"error": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"machine_type": {
|
||||||
|
"name": "machine_type",
|
||||||
|
"values": {
|
||||||
|
"classic": "classic",
|
||||||
|
"runpod-serverless": "runpod-serverless",
|
||||||
|
"modal-serverless": "modal-serverless",
|
||||||
|
"comfy-deploy-serverless": "comfy-deploy-serverless"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"workflow_run_origin": {
|
||||||
|
"name": "workflow_run_origin",
|
||||||
|
"values": {
|
||||||
|
"manual": "manual",
|
||||||
|
"api": "api",
|
||||||
|
"public-share": "public-share"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"workflow_run_status": {
|
||||||
|
"name": "workflow_run_status",
|
||||||
|
"values": {
|
||||||
|
"not-started": "not-started",
|
||||||
|
"running": "running",
|
||||||
|
"uploading": "uploading",
|
||||||
|
"success": "success",
|
||||||
|
"failed": "failed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schemas": {
|
||||||
|
"comfyui_deploy": "comfyui_deploy"
|
||||||
|
},
|
||||||
|
"_meta": {
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {},
|
||||||
|
"columns": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,756 @@
|
|||||||
|
{
|
||||||
|
"id": "db06ea66-92c2-4ebe-93c1-6cb8a90ccd8b",
|
||||||
|
"prevId": "a7d6a8dd-0e15-4165-98a2-de2a334455dc",
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "pg",
|
||||||
|
"tables": {
|
||||||
|
"api_keys": {
|
||||||
|
"name": "api_keys",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"name": "key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"org_id": {
|
||||||
|
"name": "org_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"revoked": {
|
||||||
|
"name": "revoked",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"api_keys_user_id_users_id_fk": {
|
||||||
|
"name": "api_keys_user_id_users_id_fk",
|
||||||
|
"tableFrom": "api_keys",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"api_keys_key_unique": {
|
||||||
|
"name": "api_keys_key_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"key"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deployments": {
|
||||||
|
"name": "deployments",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"org_id": {
|
||||||
|
"name": "org_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"workflow_version_id": {
|
||||||
|
"name": "workflow_version_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"workflow_id": {
|
||||||
|
"name": "workflow_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"machine_id": {
|
||||||
|
"name": "machine_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"name": "description",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"showcase_media": {
|
||||||
|
"name": "showcase_media",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"environment": {
|
||||||
|
"name": "environment",
|
||||||
|
"type": "deployment_environment",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"deployments_user_id_users_id_fk": {
|
||||||
|
"name": "deployments_user_id_users_id_fk",
|
||||||
|
"tableFrom": "deployments",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"deployments_workflow_version_id_workflow_versions_id_fk": {
|
||||||
|
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
|
||||||
|
"tableFrom": "deployments",
|
||||||
|
"tableTo": "workflow_versions",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workflow_version_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"deployments_workflow_id_workflows_id_fk": {
|
||||||
|
"name": "deployments_workflow_id_workflows_id_fk",
|
||||||
|
"tableFrom": "deployments",
|
||||||
|
"tableTo": "workflows",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workflow_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"deployments_machine_id_machines_id_fk": {
|
||||||
|
"name": "deployments_machine_id_machines_id_fk",
|
||||||
|
"tableFrom": "deployments",
|
||||||
|
"tableTo": "machines",
|
||||||
|
"columnsFrom": [
|
||||||
|
"machine_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"machines": {
|
||||||
|
"name": "machines",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"org_id": {
|
||||||
|
"name": "org_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"endpoint": {
|
||||||
|
"name": "endpoint",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"name": "disabled",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"auth_token": {
|
||||||
|
"name": "auth_token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"name": "type",
|
||||||
|
"type": "machine_type",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'classic'"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"type": "machine_status",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'ready'"
|
||||||
|
},
|
||||||
|
"snapshot": {
|
||||||
|
"name": "snapshot",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"models": {
|
||||||
|
"name": "models",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"gpu": {
|
||||||
|
"name": "gpu",
|
||||||
|
"type": "machine_gpu",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"build_machine_instance_id": {
|
||||||
|
"name": "build_machine_instance_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"build_log": {
|
||||||
|
"name": "build_log",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"machines_user_id_users_id_fk": {
|
||||||
|
"name": "machines_user_id_users_id_fk",
|
||||||
|
"tableFrom": "machines",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"name": "users",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"name": "username",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"workflow_run_outputs": {
|
||||||
|
"name": "workflow_run_outputs",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"run_id": {
|
||||||
|
"name": "run_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"name": "data",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"workflow_run_outputs_run_id_workflow_runs_id_fk": {
|
||||||
|
"name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
|
||||||
|
"tableFrom": "workflow_run_outputs",
|
||||||
|
"tableTo": "workflow_runs",
|
||||||
|
"columnsFrom": [
|
||||||
|
"run_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"workflow_runs": {
|
||||||
|
"name": "workflow_runs",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"workflow_version_id": {
|
||||||
|
"name": "workflow_version_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"workflow_inputs": {
|
||||||
|
"name": "workflow_inputs",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"workflow_id": {
|
||||||
|
"name": "workflow_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"machine_id": {
|
||||||
|
"name": "machine_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"origin": {
|
||||||
|
"name": "origin",
|
||||||
|
"type": "workflow_run_origin",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'api'"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"type": "workflow_run_status",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'not-started'"
|
||||||
|
},
|
||||||
|
"ended_at": {
|
||||||
|
"name": "ended_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
|
||||||
|
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
|
||||||
|
"tableFrom": "workflow_runs",
|
||||||
|
"tableTo": "workflow_versions",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workflow_version_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "set null",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"workflow_runs_workflow_id_workflows_id_fk": {
|
||||||
|
"name": "workflow_runs_workflow_id_workflows_id_fk",
|
||||||
|
"tableFrom": "workflow_runs",
|
||||||
|
"tableTo": "workflows",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workflow_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"workflow_runs_machine_id_machines_id_fk": {
|
||||||
|
"name": "workflow_runs_machine_id_machines_id_fk",
|
||||||
|
"tableFrom": "workflow_runs",
|
||||||
|
"tableTo": "machines",
|
||||||
|
"columnsFrom": [
|
||||||
|
"machine_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "set null",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"workflows": {
|
||||||
|
"name": "workflows",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"org_id": {
|
||||||
|
"name": "org_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"workflows_user_id_users_id_fk": {
|
||||||
|
"name": "workflows_user_id_users_id_fk",
|
||||||
|
"tableFrom": "workflows",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"workflow_versions": {
|
||||||
|
"name": "workflow_versions",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"workflow_id": {
|
||||||
|
"name": "workflow_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"workflow": {
|
||||||
|
"name": "workflow",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"workflow_api": {
|
||||||
|
"name": "workflow_api",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"name": "version",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"snapshot": {
|
||||||
|
"name": "snapshot",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"workflow_versions_workflow_id_workflows_id_fk": {
|
||||||
|
"name": "workflow_versions_workflow_id_workflows_id_fk",
|
||||||
|
"tableFrom": "workflow_versions",
|
||||||
|
"tableTo": "workflows",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workflow_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {
|
||||||
|
"deployment_environment": {
|
||||||
|
"name": "deployment_environment",
|
||||||
|
"values": {
|
||||||
|
"staging": "staging",
|
||||||
|
"production": "production",
|
||||||
|
"public-share": "public-share"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"machine_gpu": {
|
||||||
|
"name": "machine_gpu",
|
||||||
|
"values": {
|
||||||
|
"T4": "T4",
|
||||||
|
"A10G": "A10G",
|
||||||
|
"A100": "A100"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"machine_status": {
|
||||||
|
"name": "machine_status",
|
||||||
|
"values": {
|
||||||
|
"ready": "ready",
|
||||||
|
"building": "building",
|
||||||
|
"error": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"machine_type": {
|
||||||
|
"name": "machine_type",
|
||||||
|
"values": {
|
||||||
|
"classic": "classic",
|
||||||
|
"runpod-serverless": "runpod-serverless",
|
||||||
|
"modal-serverless": "modal-serverless",
|
||||||
|
"comfy-deploy-serverless": "comfy-deploy-serverless"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"workflow_run_origin": {
|
||||||
|
"name": "workflow_run_origin",
|
||||||
|
"values": {
|
||||||
|
"manual": "manual",
|
||||||
|
"api": "api",
|
||||||
|
"public-share": "public-share"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"workflow_run_status": {
|
||||||
|
"name": "workflow_run_status",
|
||||||
|
"values": {
|
||||||
|
"not-started": "not-started",
|
||||||
|
"running": "running",
|
||||||
|
"uploading": "uploading",
|
||||||
|
"success": "success",
|
||||||
|
"failed": "failed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schemas": {
|
||||||
|
"comfyui_deploy": "comfyui_deploy"
|
||||||
|
},
|
||||||
|
"_meta": {
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {},
|
||||||
|
"columns": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,762 @@
|
|||||||
|
{
|
||||||
|
"id": "1ca4fdb7-c0c4-4c39-8b47-f40282293da0",
|
||||||
|
"prevId": "db06ea66-92c2-4ebe-93c1-6cb8a90ccd8b",
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "pg",
|
||||||
|
"tables": {
|
||||||
|
"api_keys": {
|
||||||
|
"name": "api_keys",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"name": "key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"org_id": {
|
||||||
|
"name": "org_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"revoked": {
|
||||||
|
"name": "revoked",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"api_keys_user_id_users_id_fk": {
|
||||||
|
"name": "api_keys_user_id_users_id_fk",
|
||||||
|
"tableFrom": "api_keys",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"api_keys_key_unique": {
|
||||||
|
"name": "api_keys_key_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"key"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deployments": {
|
||||||
|
"name": "deployments",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"org_id": {
|
||||||
|
"name": "org_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"workflow_version_id": {
|
||||||
|
"name": "workflow_version_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"workflow_id": {
|
||||||
|
"name": "workflow_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"machine_id": {
|
||||||
|
"name": "machine_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"name": "description",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"showcase_media": {
|
||||||
|
"name": "showcase_media",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"environment": {
|
||||||
|
"name": "environment",
|
||||||
|
"type": "deployment_environment",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"deployments_user_id_users_id_fk": {
|
||||||
|
"name": "deployments_user_id_users_id_fk",
|
||||||
|
"tableFrom": "deployments",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"deployments_workflow_version_id_workflow_versions_id_fk": {
|
||||||
|
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
|
||||||
|
"tableFrom": "deployments",
|
||||||
|
"tableTo": "workflow_versions",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workflow_version_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"deployments_workflow_id_workflows_id_fk": {
|
||||||
|
"name": "deployments_workflow_id_workflows_id_fk",
|
||||||
|
"tableFrom": "deployments",
|
||||||
|
"tableTo": "workflows",
|
||||||
|
"columnsFrom": [
|
||||||
|
"workflow_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"deployments_machine_id_machines_id_fk": {
|
||||||
|
"name": "deployments_machine_id_machines_id_fk",
|
||||||
|
"tableFrom": "deployments",
|
||||||
|
"tableTo": "machines",
|
||||||
|
"columnsFrom": [
|
||||||
|
"machine_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"machines": {
|
||||||
|
"name": "machines",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"org_id": {
|
||||||
|
"name": "org_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"endpoint": {
|
||||||
|
"name": "endpoint",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"name": "disabled",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"auth_token": {
|
||||||
|
"name": "auth_token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"name": "type",
|
||||||
|
"type": "machine_type",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'classic'"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"type": "machine_status",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'ready'"
|
||||||
|
},
|
||||||
|
"snapshot": {
|
||||||
|
"name": "snapshot",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"models": {
|
||||||
|
"name": "models",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"gpu": {
|
||||||
|
"name": "gpu",
|
||||||
|
"type": "machine_gpu",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"build_machine_instance_id": {
|
||||||
|
"name": "build_machine_instance_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"build_log": {
|
||||||
|
"name": "build_log",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"machines_user_id_users_id_fk": {
|
||||||
|
"name": "machines_user_id_users_id_fk",
|
||||||
|
"tableFrom": "machines",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"name": "users",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"name": "username",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"workflow_run_outputs": {
|
||||||
|
"name": "workflow_run_outputs",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"run_id": {
|
||||||
|
"name": "run_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"name": "data",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"workflow_run_outputs_run_id_workflow_runs_id_fk": {
|
||||||
|
"name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
|
||||||
|
"tableFrom": "workflow_run_outputs",
|
||||||
|
"tableTo": "workflow_runs",
|
||||||
|
"columnsFrom": [
|
||||||
|
"run_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"workflow_runs": {
|
||||||
|
"name": "workflow_runs",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"workflow_version_id": {
|
||||||
|
"name": "workflow_version_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"workflow_inputs": {
|
||||||
|
"name": "workflow_inputs",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"workflow_id": {
|
||||||
|
"name": "workflow_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"machine_id": {
|
||||||
|
"name": "machine_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"origin": {
|
||||||
|
"name": "origin",
|
||||||
|
"type": "workflow_run_origin",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'api'"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"type": "workflow_run_status",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'not-started'"
|
||||||
|
},
|
||||||
|
"ended_at": {
|
||||||
|
"name": "ended_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"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": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,776 @@
|
|||||||
|
{
|
||||||
|
"id": "1425ee00-66fb-4541-8da7-19b217944545",
|
||||||
|
"prevId": "1ca4fdb7-c0c4-4c39-8b47-f40282293da0",
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "pg",
|
||||||
|
"tables": {
|
||||||
|
"api_keys": {
|
||||||
|
"name": "api_keys",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"name": "key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"org_id": {
|
||||||
|
"name": "org_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"revoked": {
|
||||||
|
"name": "revoked",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"api_keys_user_id_users_id_fk": {
|
||||||
|
"name": "api_keys_user_id_users_id_fk",
|
||||||
|
"tableFrom": "api_keys",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"api_keys_key_unique": {
|
||||||
|
"name": "api_keys_key_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"key"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deployments": {
|
||||||
|
"name": "deployments",
|
||||||
|
"schema": "comfyui_deploy",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"org_id": {
|
||||||
|
"name": "org_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"workflow_version_id": {
|
||||||
|
"name": "workflow_version_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"workflow_id": {
|
||||||
|
"name": "workflow_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"machine_id": {
|
||||||
|
"name": "machine_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"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": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,824 @@
|
|||||||
|
{
|
||||||
|
"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": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,830 @@
|
|||||||
|
{
|
||||||
|
"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": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -197,6 +197,55 @@
|
|||||||
"when": 1705228261543,
|
"when": 1705228261543,
|
||||||
"tag": "0027_eminent_lilith",
|
"tag": "0027_eminent_lilith",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 28,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1705642345817,
|
||||||
|
"tag": "0028_futuristic_lady_deathstrike",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 29,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1705662714161,
|
||||||
|
"tag": "0029_large_frightful_four",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 30,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1705716303820,
|
||||||
|
"tag": "0030_kind_doorman",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 31,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1705763980972,
|
||||||
|
"tag": "0031_fast_lyja",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 32,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1705806921697,
|
||||||
|
"tag": "0032_shallow_vermin",
|
||||||
|
"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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
+12
-7
@@ -12,26 +12,31 @@ let sslMode: string | boolean = process.env.SSL || "require";
|
|||||||
|
|
||||||
if (sslMode === "false") sslMode = false;
|
if (sslMode === "false") sslMode = false;
|
||||||
|
|
||||||
console.log(migrationsFolderName, sslMode);
|
let connectionString = process.env.POSTGRES_URL!;
|
||||||
|
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-4
@@ -1,4 +1,3 @@
|
|||||||
import million from 'million/compiler';
|
|
||||||
import { recmaPlugins } from "./src/mdx/recma.mjs";
|
import { recmaPlugins } from "./src/mdx/recma.mjs";
|
||||||
import { rehypePlugins } from "./src/mdx/rehype.mjs";
|
import { rehypePlugins } from "./src/mdx/rehype.mjs";
|
||||||
import { remarkPlugins } from "./src/mdx/remark.mjs";
|
import { remarkPlugins } from "./src/mdx/remark.mjs";
|
||||||
@@ -21,6 +20,8 @@ const nextConfig = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default million.next(
|
export default withSearch(withMDX(nextConfig));
|
||||||
withSearch(withMDX(nextConfig)), { auto: { rsc: true } }
|
|
||||||
);
|
// export default million.next(
|
||||||
|
// withSearch(withMDX(nextConfig)), { auto: { rsc: true } }
|
||||||
|
// );
|
||||||
|
|||||||
+8
-12
@@ -12,7 +12,8 @@
|
|||||||
"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",
|
||||||
@@ -60,6 +61,7 @@
|
|||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
"drizzle-orm": "^0.29.1",
|
"drizzle-orm": "^0.29.1",
|
||||||
"drizzle-zod": "^0.5.1",
|
"drizzle-zod": "^0.5.1",
|
||||||
|
"embla-carousel-react": "^8.0.0-rc19",
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.2",
|
||||||
"flexsearch": "^0.7.31",
|
"flexsearch": "^0.7.31",
|
||||||
"framer-motion": "^10.16.16",
|
"framer-motion": "^10.16.16",
|
||||||
@@ -70,12 +72,15 @@
|
|||||||
"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.0.4",
|
"next": "14.1",
|
||||||
"next-plausible": "^3.12.0",
|
"next-plausible": "^3.12.0",
|
||||||
"next-themes": "^0.2.1",
|
"next-themes": "^0.2.1",
|
||||||
"next-usequerystate": "^1.13.2",
|
"next-usequerystate": "^1.13.2",
|
||||||
"pg": "^8.11.3",
|
"pg": "^8.11.3",
|
||||||
|
"posthog-js": "^1.100.0",
|
||||||
|
"posthog-node": "^3.5.0",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-day-picker": "^8.9.1",
|
"react-day-picker": "^8.9.1",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
@@ -102,26 +107,17 @@
|
|||||||
"zustand": "^4.4.7"
|
"zustand": "^4.4.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@trivago/prettier-plugin-sort-imports": "4.1.1",
|
"@biomejs/biome": "1.5.2",
|
||||||
"@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"
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
@@ -0,0 +1,9 @@
|
|||||||
|
import { SharePageSettings } from "@/components/SharePageSettings";
|
||||||
|
|
||||||
|
export default async function Page({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: { share_id: string };
|
||||||
|
}) {
|
||||||
|
return <SharePageSettings deployment_id={params.share_id} />;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import type { FC } from "react";
|
||||||
|
|
||||||
|
const Default: FC = () => {
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Default;
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// app/PostHogPageView.tsx
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { usePathname, useSearchParams } from "next/navigation";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { usePostHog } from 'posthog-js/react';
|
||||||
|
|
||||||
|
export default function PostHogPageView() {
|
||||||
|
const pathname = usePathname();
|
||||||
|
const searchParams = useSearchParams();
|
||||||
|
const posthog = usePostHog();
|
||||||
|
// Track pageviews
|
||||||
|
useEffect(() => {
|
||||||
|
if (pathname && posthog) {
|
||||||
|
let url = window.origin + pathname
|
||||||
|
if (searchParams.toString()) {
|
||||||
|
url = url + `?${searchParams.toString()}`
|
||||||
|
}
|
||||||
|
posthog.capture(
|
||||||
|
'$pageview',
|
||||||
|
{
|
||||||
|
'$current_url': url,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}, [pathname, searchParams, posthog])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
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";
|
||||||
@@ -6,7 +5,11 @@ 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
|
||||||
|
|
||||||
@@ -16,14 +19,24 @@ declare module "hono" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkAuth(c: Context, next: Next) {
|
async function checkAuth(c: Context, next: Next, headers?: HeadersInit) {
|
||||||
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", 401);
|
return c.text("Invalid or expired token", {
|
||||||
} else {
|
status: 401,
|
||||||
|
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) return c.text("Revoked token", 401);
|
if (revokedKey)
|
||||||
|
return c.text("Revoked token", {
|
||||||
|
status: 401,
|
||||||
|
headers: headers,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
c.set("apiKeyTokenData", userData);
|
c.set("apiKeyTokenData", userData);
|
||||||
@@ -31,18 +44,35 @@ async function checkAuth(c: Context, next: Next) {
|
|||||||
await next();
|
await next();
|
||||||
}
|
}
|
||||||
|
|
||||||
app.use("/run", async (c, next) => {
|
app.use("/run", checkAuth);
|
||||||
return checkAuth(c, next);
|
app.use("/upload-url", checkAuth);
|
||||||
|
|
||||||
|
const corsHandler = cors({
|
||||||
|
origin: "*",
|
||||||
|
allowHeaders: ["Authorization", "Content-Type"],
|
||||||
|
allowMethods: ["POST", "GET", "OPTIONS"],
|
||||||
|
exposeHeaders: ["Content-Length"],
|
||||||
|
maxAge: 600,
|
||||||
|
credentials: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use("/upload-url", async (c, next) => {
|
// CORS Check
|
||||||
return checkAuth(c, next);
|
app.use("/workflow", corsHandler, checkAuth);
|
||||||
});
|
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",
|
||||||
@@ -69,3 +99,4 @@ const handler = handle(app);
|
|||||||
|
|
||||||
export const GET = handler;
|
export const GET = handler;
|
||||||
export const POST = handler;
|
export const POST = handler;
|
||||||
|
export const OPTIONS = handler;
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
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(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -29,7 +30,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 =
|
||||||
@@ -38,7 +39,7 @@ export async function GET(request: Request) {
|
|||||||
{
|
{
|
||||||
error: errorMessage,
|
error: errorMessage,
|
||||||
},
|
},
|
||||||
{ status: 500 }
|
{ status: 500 },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
import { createNewWorkflow } from "../../../../server/createNewWorkflow";
|
import { snapshotType, workflowAPIType, workflowType } from "@/db/schema";
|
||||||
import { parseJWT } from "../../../../server/parseJWT";
|
|
||||||
import { db } from "@/db/db";
|
|
||||||
import {
|
|
||||||
snapshotType,
|
|
||||||
workflowAPIType,
|
|
||||||
workflowType,
|
|
||||||
workflowVersionTable,
|
|
||||||
} from "@/db/schema";
|
|
||||||
import { parseDataSafe } from "@/lib/parseDataSafe";
|
import { parseDataSafe } from "@/lib/parseDataSafe";
|
||||||
import { 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": "*",
|
||||||
@@ -54,7 +52,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;
|
||||||
@@ -74,7 +72,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({
|
||||||
@@ -90,48 +88,17 @@ 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 data = await db
|
const { version: _version } = await createNewWorkflowVersion({
|
||||||
.insert(workflowVersionTable)
|
workflow_id: workflow_id,
|
||||||
.values({
|
workflowData: {
|
||||||
workflow_id,
|
workflow,
|
||||||
workflow: workflow,
|
|
||||||
workflow_api,
|
workflow_api,
|
||||||
// version: sql`${workflowVersionTable.version} + 1`,
|
snapshot,
|
||||||
snapshot: snapshot,
|
},
|
||||||
version: sql`(
|
});
|
||||||
SELECT COALESCE(MAX(version), 0) + 1
|
version = _version;
|
||||||
FROM ${workflowVersionTable}
|
|
||||||
WHERE workflow_id = ${workflow_id}
|
|
||||||
)`,
|
|
||||||
})
|
|
||||||
.returning();
|
|
||||||
version = data[0].version;
|
|
||||||
} else {
|
} else {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{
|
{
|
||||||
@@ -141,7 +108,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) {
|
||||||
@@ -153,7 +120,7 @@ export async function POST(request: Request) {
|
|||||||
status: 500,
|
status: 500,
|
||||||
statusText: "Invalid request",
|
statusText: "Invalid request",
|
||||||
headers: corsHeaders,
|
headers: corsHeaders,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,6 +132,6 @@ export async function POST(request: Request) {
|
|||||||
{
|
{
|
||||||
status: 200,
|
status: 200,
|
||||||
headers: corsHeaders,
|
headers: corsHeaders,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { ErrorFullPage } from "@/components/docs/ErrorPage";
|
||||||
|
|
||||||
|
export default ErrorFullPage;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { LoadingPageWrapper } from "@/components/LoadingWrapper";
|
||||||
|
import { usePathname } from "next/navigation";
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
const pathName = usePathname();
|
||||||
|
return <LoadingPageWrapper className="h-full" tag={pathName.toLowerCase()} />;
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <Examples />;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type exampleWorkflow = {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
previewURL: string;
|
||||||
|
image: {
|
||||||
|
src: string,
|
||||||
|
alt: string,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const exampleWorkflows: exampleWorkflow[] = [
|
||||||
|
{
|
||||||
|
title: "Txt2Img SDXL",
|
||||||
|
description: "The basic workflow, type a prompt and generate images based on that.",
|
||||||
|
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-txt2img-sdxl',
|
||||||
|
image: {
|
||||||
|
src: '/example-workflows/txt2img.webp',
|
||||||
|
alt: 'IPAdapter workflow',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Txt2Img LCM SDXL",
|
||||||
|
description: "Images in a couple of seconds, increase the speed of each generation using LCM Lora.",
|
||||||
|
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-lcm-sdxl',
|
||||||
|
image: {
|
||||||
|
src: '/example-workflows/txt2img-lcm.webp',
|
||||||
|
alt: 'txt2img LCM SDXL',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "IPAdapter SDXL",
|
||||||
|
description: "Load images and use them as reference for new generations.",
|
||||||
|
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-ip-adapter-sdxl',
|
||||||
|
image: {
|
||||||
|
src: '/example-workflows/ipadapter.webp',
|
||||||
|
alt: 'IPAdapter workflow',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Upscale and Add Detail SDXL",
|
||||||
|
description: "Upscale and Add Details to your creations",
|
||||||
|
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-upscale-and-add-detail-sdxl',
|
||||||
|
image: {
|
||||||
|
src: '/example-workflows/upscale.webp',
|
||||||
|
alt: 'Upscale and Add Detail SDXL',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
async function Examples() {
|
||||||
|
return (
|
||||||
|
<div className="w-full py-4">
|
||||||
|
<section className="mx-auto flex max-w-[980px] flex-col items-center gap-2 py-8 md:py-12 md:pb-8 lg:py-24 lg:pb-20">
|
||||||
|
<h1 className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl text-center">
|
||||||
|
Check out some examples
|
||||||
|
</h1>
|
||||||
|
<p className="max-w-[560px] text-center text-lg text-muted-foreground">Text to Image, Image to Image, IPAdapter, and more. Here are some examples that you can use to deploy your workflow.</p>
|
||||||
|
</section>
|
||||||
|
<section className="flex justify-center flex-wrap gap-4">
|
||||||
|
{exampleWorkflows.map(workflow => {
|
||||||
|
return <Card className="w-[350px]">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>{workflow.title}</CardTitle>
|
||||||
|
<CardDescription>{workflow.description}</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<Image src={workflow.image.src} alt={workflow.image.alt} width={350} height={230} />
|
||||||
|
</CardContent>
|
||||||
|
<CardFooter className="flex justify-end gap-2">
|
||||||
|
<Button asChild>
|
||||||
|
<Link href={workflow.previewURL}>View Workflow</Link>
|
||||||
|
</Button>
|
||||||
|
</CardFooter>
|
||||||
|
</Card>;
|
||||||
|
})}
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,13 +1,19 @@
|
|||||||
import { Navbar } from "../../components/Navbar";
|
import { Navbar } from "../../components/Navbar";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
import { PHProvider } from "./providers";
|
||||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||||
import { ClerkProvider } from "@clerk/nextjs";
|
import { ClerkProvider } from "@clerk/nextjs";
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import meta from "next-gen/config";
|
import meta from "next-gen/config";
|
||||||
import PlausibleProvider from "next-plausible";
|
import PlausibleProvider from "next-plausible";
|
||||||
|
import dynamic from "next/dynamic";
|
||||||
import { Inter } from "next/font/google";
|
import { Inter } from "next/font/google";
|
||||||
import { Toaster } from "sonner";
|
import { Toaster } from "sonner";
|
||||||
|
|
||||||
|
const PostHogPageView = dynamic(() => import("./PostHogPageView"), {
|
||||||
|
ssr: false,
|
||||||
|
});
|
||||||
|
|
||||||
const inter = Inter({ subsets: ["latin"] });
|
const inter = Inter({ subsets: ["latin"] });
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
@@ -27,8 +33,10 @@ export const metadata: Metadata = {
|
|||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
children,
|
children,
|
||||||
|
modal,
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
|
modal: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
@@ -39,20 +47,24 @@ export default function RootLayout({
|
|||||||
<PlausibleProvider domain={process.env.PLAUSIBLE_DOMAIN} />
|
<PlausibleProvider domain={process.env.PLAUSIBLE_DOMAIN} />
|
||||||
</head>
|
</head>
|
||||||
)}
|
)}
|
||||||
<body className={inter.className}>
|
<PHProvider>
|
||||||
<main className="w-full flex min-h-[100dvh] flex-col items-center justify-start">
|
<body className={inter.className}>
|
||||||
<div className="z-[-1] fixed h-full w-full bg-white">
|
<PostHogPageView />
|
||||||
<div className="absolute h-full w-full bg-[radial-gradient(#e5e7eb_1px,transparent_1px)] [background-size:16px_16px] [mask-image:radial-gradient(ellipse_50%_50%_at_50%_50%,#000_70%,transparent_100%)]" />
|
<main className="w-full flex min-h-[100dvh] flex-col items-center justify-start">
|
||||||
</div>
|
<div className="z-[-1] fixed h-full w-full bg-white">
|
||||||
<div className="sticky w-full h-18 flex items-center justify-between gap-4 p-4 border-b border-gray-200">
|
<div className="absolute h-full w-full bg-[radial-gradient(#e5e7eb_1px,transparent_1px)] [background-size:16px_16px] [mask-image:radial-gradient(ellipse_50%_50%_at_50%_50%,#000_70%,transparent_100%)]" />
|
||||||
<Navbar />
|
</div>
|
||||||
</div>
|
<div className="sticky w-full h-18 flex items-center justify-between gap-4 p-4 border-b border-gray-200">
|
||||||
<div className="md:px-10 px-6 w-full h-[calc(100dvh-73px)]">
|
<Navbar />
|
||||||
{children}
|
</div>
|
||||||
</div>
|
<div className="md:px-10 px-6 w-full h-[calc(100dvh-73px)]">
|
||||||
<Toaster richColors />
|
{children}
|
||||||
</main>
|
</div>
|
||||||
</body>
|
<Toaster richColors />
|
||||||
|
{modal}
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</PHProvider>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
</ClerkProvider>
|
</ClerkProvider>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// app/providers.tsx
|
||||||
|
'use client'
|
||||||
|
import posthog from 'posthog-js'
|
||||||
|
import { PostHogProvider } from 'posthog-js/react'
|
||||||
|
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
|
||||||
|
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
||||||
|
capture_pageview: false // Disable automatic pageview capture, as we capture manually
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PHProvider({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode
|
||||||
|
}) {
|
||||||
|
return <PostHogProvider client={posthog}>{children}</PostHogProvider>
|
||||||
|
}
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
import { ButtonActionMenu } from "@/components/ButtonActionLoader";
|
import { ButtonActionMenu } from "@/components/ButtonActionLoader";
|
||||||
|
import { RunWorkflowInline } from "@/components/RunWorkflowInline";
|
||||||
|
import { PublicRunOutputs } from "@/components/VersionSelect";
|
||||||
import {
|
import {
|
||||||
PublicRunOutputs,
|
Card,
|
||||||
RunWorkflowInline,
|
CardContent,
|
||||||
} from "@/components/VersionSelect";
|
CardDescription,
|
||||||
import {
|
CardHeader,
|
||||||
Card,
|
CardTitle,
|
||||||
CardContent,
|
|
||||||
CardDescription,
|
|
||||||
CardHeader,
|
|
||||||
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";
|
||||||
@@ -16,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";
|
||||||
@@ -27,84 +25,87 @@ 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>
|
||||||
<RunWorkflowInline
|
<div>
|
||||||
inputs={inputs}
|
{sharedDeployment?.description && sharedDeployment?.description}
|
||||||
machine_id={sharedDeployment.machine_id}
|
</div>
|
||||||
workflow_version_id={sharedDeployment.workflow_version_id}
|
<RunWorkflowInline
|
||||||
/>
|
inputs={inputs}
|
||||||
</CardContent>
|
machine_id={sharedDeployment.machine_id}
|
||||||
</Card>
|
workflow_version_id={sharedDeployment.workflow_version_id}
|
||||||
<Card className="w-full h-fit mt-4">
|
/>
|
||||||
<CardHeader>
|
</CardContent>
|
||||||
<CardDescription>Run outputs</CardDescription>
|
</Card>
|
||||||
</CardHeader>
|
<Card className="w-full h-fit mt-4">
|
||||||
|
<CardHeader>
|
||||||
|
<CardDescription>Run outputs</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<PublicRunOutputs />
|
<PublicRunOutputs preview={sharedDeployment.showcase_media} />
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { SharePageSettings } from "@/components/SharePageSettings";
|
||||||
|
|
||||||
|
export default async function Page({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: { share_id: string };
|
||||||
|
}) {
|
||||||
|
return <SharePageSettings deployment_id={params.share_id} />;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import ErrorPage from "@/components/docs/ErrorPage";
|
||||||
|
|
||||||
|
export default ErrorPage;
|
||||||
@@ -1,51 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button";
|
import ErrorPage from "@/components/docs/ErrorPage";
|
||||||
import {
|
|
||||||
Card,
|
|
||||||
CardDescription,
|
|
||||||
CardHeader,
|
|
||||||
CardTitle,
|
|
||||||
} from "@/components/ui/card";
|
|
||||||
// Error components must be Client Components
|
|
||||||
import { useEffect } from "react";
|
|
||||||
|
|
||||||
export default function Error({
|
export default ErrorPage;
|
||||||
error,
|
|
||||||
reset,
|
|
||||||
}: {
|
|
||||||
error?: Error & { digest?: string };
|
|
||||||
reset?: () => void;
|
|
||||||
}) {
|
|
||||||
useEffect(() => {
|
|
||||||
// Log the error to an error reporting service
|
|
||||||
console.log(error?.message);
|
|
||||||
}, [error]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="border rounded-2xl flex flex-col w-full gap-20 justify-center items-center">
|
|
||||||
<Card className="max-w-2xl">
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle>
|
|
||||||
<div className="text-2xl">Something went wrong!</div>
|
|
||||||
</CardTitle>
|
|
||||||
<CardDescription
|
|
||||||
suppressHydrationWarning={true}
|
|
||||||
className="flex flex-col gap-4"
|
|
||||||
>
|
|
||||||
<div className="text-lg">{error?.message}</div>
|
|
||||||
<Button
|
|
||||||
className="w-full"
|
|
||||||
onClick={
|
|
||||||
// Attempt to recover by trying to re-render the segment
|
|
||||||
() => reset?.()
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Try again
|
|
||||||
</Button>
|
|
||||||
</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export default async function Page({
|
|||||||
<CardHeader className="relative">
|
<CardHeader className="relative">
|
||||||
<CardTitle>Run</CardTitle>
|
<CardTitle>Run</CardTitle>
|
||||||
<div className="absolute right-6 top-6">
|
<div className="absolute right-6 top-6">
|
||||||
<RouteRefresher interval={5000} />
|
<RouteRefresher interval={5000} autoRefresh={false} />
|
||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import ErrorPage from "@/components/docs/ErrorPage";
|
||||||
|
|
||||||
|
export default ErrorPage;
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
|
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,
|
||||||
@@ -48,6 +49,7 @@ 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,6 +1,3 @@
|
|||||||
import Error from "@/app/(app)/workflows/[workflow_id]/@runs/error";
|
|
||||||
import { ErrorBoundary } from "@/components/ErrorBoundary";
|
|
||||||
|
|
||||||
export default async function Layout({
|
export default async function Layout({
|
||||||
children,
|
children,
|
||||||
deployment,
|
deployment,
|
||||||
@@ -13,15 +10,13 @@ export default async function Layout({
|
|||||||
workflow: React.ReactNode;
|
workflow: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary fallback={<Error />}>
|
<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)]">
|
<div className="w-full flex gap-4 flex-col min-w-0">
|
||||||
<div className="w-full flex gap-4 flex-col min-w-0">
|
{workflow}
|
||||||
{workflow}
|
{deployment}
|
||||||
{deployment}
|
|
||||||
</div>
|
|
||||||
{runs}
|
|
||||||
{children}
|
|
||||||
</div>
|
</div>
|
||||||
</ErrorBoundary>
|
{runs}
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
import { setInitialUserData } from "../../../lib/setInitialUserData";
|
import { setInitialUserData } from "../../../lib/setInitialUserData";
|
||||||
|
import { getAllUserWorkflow } from "../../../server/crudWorkflow";
|
||||||
import { WorkflowList } from "@/components/WorkflowList";
|
import { WorkflowList } from "@/components/WorkflowList";
|
||||||
import { db } from "@/db/db";
|
import { db } from "@/db/db";
|
||||||
import { usersTable, workflowTable, workflowVersionTable } from "@/db/schema";
|
import { usersTable } from "@/db/schema";
|
||||||
import { auth } from "@clerk/nextjs";
|
import { auth } from "@clerk/nextjs";
|
||||||
import { and, desc, eq, isNull } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return <WorkflowServer />;
|
return <WorkflowServer />;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function WorkflowServer() {
|
async function WorkflowServer() {
|
||||||
const { userId, orgId } = await auth();
|
const { userId } = await auth();
|
||||||
|
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
return <div>No auth</div>;
|
return <div>No auth</div>;
|
||||||
@@ -24,35 +25,11 @@ async function WorkflowServer() {
|
|||||||
await setInitialUserData(userId);
|
await setInitialUserData(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const workflow = await db.query.workflowTable.findMany({
|
const workflow = await getAllUserWorkflow();
|
||||||
// extras: {
|
|
||||||
// count: sql<number>`(select count(*) from ${workflowVersionTable})`.as(
|
|
||||||
// "count",
|
|
||||||
// ),
|
|
||||||
// },
|
|
||||||
with: {
|
|
||||||
versions: {
|
|
||||||
limit: 1,
|
|
||||||
orderBy: desc(workflowVersionTable.version),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
orderBy: desc(workflowTable.updated_at),
|
|
||||||
where:
|
|
||||||
orgId != undefined
|
|
||||||
? eq(workflowTable.org_id, orgId)
|
|
||||||
: and(eq(workflowTable.user_id, userId), isNull(workflowTable.org_id)),
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
if (!workflow) {
|
||||||
<WorkflowList
|
return <div>No workflow found</div>;
|
||||||
data={workflow.map((x) => {
|
}
|
||||||
return {
|
|
||||||
id: x.id,
|
return <WorkflowList data={workflow} />;
|
||||||
email: x.name,
|
|
||||||
amount: x.versions[0]?.version ?? 0,
|
|
||||||
date: x.updated_at,
|
|
||||||
};
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
|
import { useAuth, useClerk } from "@clerk/nextjs";
|
||||||
import { MoreVertical } from "lucide-react";
|
import { MoreVertical } from "lucide-react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
@@ -16,9 +17,11 @@ 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);
|
||||||
@@ -33,7 +36,10 @@ export function ButtonAction({
|
|||||||
await callServerPromise(action());
|
await callServerPromise(action());
|
||||||
setPending(false);
|
setPending(false);
|
||||||
|
|
||||||
router.refresh();
|
if (routerAction === "back") {
|
||||||
|
router.back();
|
||||||
|
router.refresh();
|
||||||
|
} else if (routerAction === "refresh") router.refresh();
|
||||||
}}
|
}}
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
@@ -49,7 +55,9 @@ export function ButtonActionMenu(props: {
|
|||||||
action: () => Promise<any>;
|
action: () => Promise<any>;
|
||||||
}[];
|
}[];
|
||||||
}) {
|
}) {
|
||||||
|
const user = useAuth();
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const clerk = useClerk();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
@@ -64,6 +72,13 @@ export function ButtonActionMenu(props: {
|
|||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
key={action.title}
|
key={action.title}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
if (!user.isSignedIn) {
|
||||||
|
clerk.openSignIn({
|
||||||
|
redirectUrl: window.location.href,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
await callServerPromise(action.action());
|
await callServerPromise(action.action());
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
"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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
import { ButtonAction } from "@/components/ButtonActionLoader";
|
|
||||||
import { CodeBlock } from "@/components/CodeBlock";
|
import { CodeBlock } from "@/components/CodeBlock";
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -10,15 +8,11 @@ import {
|
|||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||||
import { TableCell, TableRow } from "@/components/ui/table";
|
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 { getRelativeTime } from "@/lib/getRelativeTime";
|
|
||||||
import { removePublicShareDeployment } from "@/server/curdDeploments";
|
|
||||||
import type { findAllDeployments } from "@/server/findAllRuns";
|
import type { findAllDeployments } from "@/server/findAllRuns";
|
||||||
import { ExternalLink } from "lucide-react";
|
import { DeploymentRow, SharePageDeploymentRow } from "./DeploymentRow";
|
||||||
import { headers } from "next/headers";
|
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
const curlTemplate = `
|
const curlTemplate = `
|
||||||
curl --request POST \
|
curl --request POST \
|
||||||
@@ -61,64 +55,51 @@ const output = fetch("<URL>?run_id=" + run_id, {
|
|||||||
}).then(response => response.json())
|
}).then(response => response.json())
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const clientTemplate = `
|
const jsClientSetupTemplate = `
|
||||||
const client = new ComfyDeployClient({
|
const client = new ComfyDeployClient({
|
||||||
apiBase: "<URLONLY>",
|
apiBase: "<URLONLY>",
|
||||||
apiToken: process.env.COMFY_DEPLOY_API_KEY!,
|
apiToken: process.env.COMFY_DEPLOY_API_KEY!,
|
||||||
});
|
});
|
||||||
|
`;
|
||||||
|
|
||||||
export async function generateTextures(scrImageId: string) {
|
const jsClientSetupTemplateHostedVersion = `
|
||||||
const result = await client.run("<ID>", {
|
const client = new ComfyDeployClient({
|
||||||
input_image: "",
|
apiToken: process.env.COMFY_DEPLOY_API_KEY!,
|
||||||
});
|
});
|
||||||
if (!result || !result.run_id) return { error: "run id not found" };
|
`;
|
||||||
return { id: result.run_id };
|
|
||||||
}
|
const jsClientCreateRunTemplate = `
|
||||||
|
const { run_id } = await client.run("<ID>", {
|
||||||
|
inputs: {}
|
||||||
|
});
|
||||||
|
`;
|
||||||
|
|
||||||
|
const jsClientCreateRunNoInputsTemplate = `
|
||||||
|
const { run_id } = await client.run("<ID>");
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const clientTemplate_checkStatus = `
|
const clientTemplate_checkStatus = `
|
||||||
const run_id = "<RUN_ID>";
|
const run = await client.getRun(run_id);
|
||||||
|
|
||||||
while (true) {
|
|
||||||
const run = await client.getRun(run_id);
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
||||||
|
|
||||||
if (!run) continue;
|
|
||||||
run.outputs.map((val) => {
|
|
||||||
if (!val.data.image) return;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function DeploymentDisplay({
|
export function DeploymentDisplay({
|
||||||
deployment,
|
deployment,
|
||||||
|
domain,
|
||||||
}: {
|
}: {
|
||||||
deployment: Awaited<ReturnType<typeof findAllDeployments>>[0];
|
deployment: Awaited<ReturnType<typeof findAllDeployments>>[0];
|
||||||
|
domain: string;
|
||||||
}) {
|
}) {
|
||||||
const headersList = headers();
|
|
||||||
const host = headersList.get("host") || "";
|
|
||||||
const protocol = headersList.get("x-forwarded-proto") || "";
|
|
||||||
const domain = `${protocol}://${host}`;
|
|
||||||
|
|
||||||
const workflowInput = getInputsFromWorkflow(deployment.version);
|
const workflowInput = getInputsFromWorkflow(deployment.version);
|
||||||
|
|
||||||
|
if (deployment.environment === "public-share") {
|
||||||
|
return <SharePageDeploymentRow deployment={deployment} />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog>
|
<Dialog>
|
||||||
<DialogTrigger asChild className="appearance-none hover:cursor-pointer">
|
<DialogTrigger asChild className="appearance-none hover:cursor-pointer">
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell className="capitalize truncate">
|
<DeploymentRow deployment={deployment} />
|
||||||
{deployment.environment}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="font-medium truncate">
|
|
||||||
{deployment.version?.version}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="font-medium truncate">
|
|
||||||
{deployment.machine?.name}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="text-right truncate">
|
|
||||||
{getRelativeTime(deployment.updated_at)}
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent className="max-w-3xl">
|
<DialogContent className="max-w-3xl">
|
||||||
@@ -129,94 +110,80 @@ export function DeploymentDisplay({
|
|||||||
<DialogDescription>Code for your deployment client</DialogDescription>
|
<DialogDescription>Code for your deployment client</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<ScrollArea className="max-h-[600px] pr-4">
|
<ScrollArea className="max-h-[600px] pr-4">
|
||||||
{deployment.environment !== "public-share" ? (
|
<Tabs defaultValue="client" className="w-full gap-2 text-sm">
|
||||||
<Tabs defaultValue="client" className="w-full gap-2">
|
<TabsList className="grid w-fit grid-cols-3 mb-2">
|
||||||
<TabsList className="grid w-fit grid-cols-3">
|
<TabsTrigger value="client">Server Client</TabsTrigger>
|
||||||
<TabsTrigger value="client">client</TabsTrigger>
|
<TabsTrigger value="js">NodeJS Fetch</TabsTrigger>
|
||||||
<TabsTrigger value="js">js</TabsTrigger>
|
<TabsTrigger value="curl">CURL</TabsTrigger>
|
||||||
<TabsTrigger value="curl">curl</TabsTrigger>
|
</TabsList>
|
||||||
</TabsList>
|
<TabsContent className="flex flex-col gap-2 !mt-0" value="client">
|
||||||
<TabsContent className="flex flex-col gap-2 !mt-0" value="client">
|
<div>
|
||||||
<div>
|
Copy and paste the ComfyDeployClient form
|
||||||
Trigger the workflow with
|
<a
|
||||||
<a
|
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"
|
||||||
>
|
|
||||||
comfy deploy wrapper
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
Copy the wrapper to your project, and import the function
|
|
||||||
</div>
|
|
||||||
<CodeBlock
|
|
||||||
lang="js"
|
|
||||||
code={formatCode(
|
|
||||||
clientTemplate,
|
|
||||||
deployment,
|
|
||||||
domain,
|
|
||||||
workflowInput
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
Check the status of the run, and retrieve the outputs
|
|
||||||
<CodeBlock
|
|
||||||
lang="js"
|
|
||||||
code={formatCode(
|
|
||||||
clientTemplate_checkStatus,
|
|
||||||
deployment,
|
|
||||||
domain
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</TabsContent>
|
|
||||||
<TabsContent className="flex flex-col gap-2 !mt-0" value="js">
|
|
||||||
Trigger the workflow
|
|
||||||
<CodeBlock
|
|
||||||
lang="js"
|
|
||||||
code={formatCode(
|
|
||||||
jsTemplate,
|
|
||||||
deployment,
|
|
||||||
domain,
|
|
||||||
workflowInput
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
Check the status of the run, and retrieve the outputs
|
|
||||||
<CodeBlock
|
|
||||||
lang="js"
|
|
||||||
code={formatCode(jsTemplate_checkStatus, deployment, domain)}
|
|
||||||
/>
|
|
||||||
</TabsContent>
|
|
||||||
<TabsContent className="flex flex-col gap-2 !mt-2" value="curl">
|
|
||||||
<CodeBlock
|
|
||||||
lang="bash"
|
|
||||||
code={formatCode(curlTemplate, deployment, domain)}
|
|
||||||
/>
|
|
||||||
<CodeBlock
|
|
||||||
lang="bash"
|
|
||||||
code={formatCode(
|
|
||||||
curlTemplate_checkStatus,
|
|
||||||
deployment,
|
|
||||||
domain
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</TabsContent>
|
|
||||||
</Tabs>
|
|
||||||
) : (
|
|
||||||
<div className="w-full justify-end flex gap-2 py-1">
|
|
||||||
<Button asChild className="gap-2" variant="outline" type="submit">
|
|
||||||
<ButtonAction
|
|
||||||
action={removePublicShareDeployment.bind(null, deployment.id)}
|
|
||||||
>
|
>
|
||||||
Remove
|
here
|
||||||
</ButtonAction>
|
</a>
|
||||||
</Button>
|
</div>
|
||||||
<Button asChild className="gap-2">
|
<CodeBlock
|
||||||
<Link href={`/share/${deployment.id}`} target="_blank">
|
lang="js"
|
||||||
View Share Page <ExternalLink size={14} />
|
code={formatCode(
|
||||||
</Link>
|
domain == "https://www.comfydeploy.com"
|
||||||
</Button>
|
? jsClientSetupTemplateHostedVersion
|
||||||
</div>
|
: jsClientSetupTemplate,
|
||||||
)}
|
deployment,
|
||||||
|
domain,
|
||||||
|
workflowInput,
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
Create a run via deployment id
|
||||||
|
<CodeBlock
|
||||||
|
lang="js"
|
||||||
|
code={formatCode(
|
||||||
|
workflowInput && workflowInput.length > 0
|
||||||
|
? jsClientCreateRunTemplate
|
||||||
|
: jsClientCreateRunNoInputsTemplate,
|
||||||
|
deployment,
|
||||||
|
domain,
|
||||||
|
workflowInput,
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
Check the status of the run, and retrieve the outputs
|
||||||
|
<CodeBlock
|
||||||
|
lang="js"
|
||||||
|
code={formatCode(
|
||||||
|
clientTemplate_checkStatus,
|
||||||
|
deployment,
|
||||||
|
domain,
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</TabsContent>
|
||||||
|
<TabsContent className="flex flex-col gap-2 !mt-0" value="js">
|
||||||
|
Trigger the workflow
|
||||||
|
<CodeBlock
|
||||||
|
lang="js"
|
||||||
|
code={formatCode(jsTemplate, deployment, domain, workflowInput)}
|
||||||
|
/>
|
||||||
|
Check the status of the run, and retrieve the outputs
|
||||||
|
<CodeBlock
|
||||||
|
lang="js"
|
||||||
|
code={formatCode(jsTemplate_checkStatus, deployment, domain)}
|
||||||
|
/>
|
||||||
|
</TabsContent>
|
||||||
|
<TabsContent className="flex flex-col gap-2 !mt-2" value="curl">
|
||||||
|
<CodeBlock
|
||||||
|
lang="bash"
|
||||||
|
code={formatCode(curlTemplate, deployment, domain)}
|
||||||
|
/>
|
||||||
|
<CodeBlock
|
||||||
|
lang="bash"
|
||||||
|
code={formatCode(curlTemplate_checkStatus, deployment, domain)}
|
||||||
|
/>
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
@@ -227,7 +194,8 @@ function formatCode(
|
|||||||
codeTemplate: string,
|
codeTemplate: string,
|
||||||
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,
|
||||||
) {
|
) {
|
||||||
if (inputs && inputs.length > 0) {
|
if (inputs && inputs.length > 0) {
|
||||||
codeTemplate = codeTemplate.replace(
|
codeTemplate = codeTemplate.replace(
|
||||||
@@ -236,20 +204,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
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { TableCell, TableRow } from "@/components/ui/table";
|
||||||
|
import { getRelativeTime } from "@/lib/getRelativeTime";
|
||||||
|
import type { findAllDeployments } from "@/server/findAllRuns";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
export function SharePageDeploymentRow({
|
||||||
|
deployment,
|
||||||
|
}: {
|
||||||
|
deployment: Awaited<ReturnType<typeof findAllDeployments>>[0];
|
||||||
|
}) {
|
||||||
|
const router = useRouter();
|
||||||
|
return (
|
||||||
|
<TableRow
|
||||||
|
className="appearance-none hover:cursor-pointer"
|
||||||
|
onClick={() => {
|
||||||
|
if (deployment.environment === "public-share") {
|
||||||
|
router.push(
|
||||||
|
`/share/${deployment.share_slug ?? deployment.id}/settings`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TableCell className="capitalize truncate">
|
||||||
|
{deployment.environment}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="font-medium truncate">
|
||||||
|
{deployment.version?.version}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="font-medium truncate">
|
||||||
|
{deployment.machine?.name}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-right truncate">
|
||||||
|
{getRelativeTime(deployment.updated_at)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DeploymentRow({
|
||||||
|
deployment,
|
||||||
|
}: {
|
||||||
|
deployment: Awaited<ReturnType<typeof findAllDeployments>>[0];
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<TableCell className="capitalize truncate">
|
||||||
|
{deployment.environment}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="font-medium truncate">
|
||||||
|
{deployment.version?.version}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="font-medium truncate">
|
||||||
|
{deployment.machine?.name}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-right truncate">
|
||||||
|
{getRelativeTime(deployment.updated_at)}
|
||||||
|
</TableCell>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
DialogDescription,
|
DialogDescription,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
@@ -91,7 +92,7 @@ export function InsertModal<
|
|||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<AutoFormSubmit>
|
<AutoFormSubmit>
|
||||||
Save Changes
|
Save Changes
|
||||||
<span className="ml-2">{isLoading && <LoadingIcon />}</span>
|
{isLoading && <LoadingIcon />}
|
||||||
</AutoFormSubmit>
|
</AutoFormSubmit>
|
||||||
</div>
|
</div>
|
||||||
</AutoForm>
|
</AutoForm>
|
||||||
@@ -106,12 +107,14 @@ export function UpdateModal<
|
|||||||
Y extends UnknownKeysParam,
|
Y extends UnknownKeysParam,
|
||||||
Z extends ZodObject<K, Y>
|
Z extends ZodObject<K, Y>
|
||||||
>(props: {
|
>(props: {
|
||||||
open: boolean;
|
open?: boolean;
|
||||||
setOpen: (open: boolean) => void;
|
setOpen?: (open: boolean) => void;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
dialogClassName?: string;
|
dialogClassName?: string;
|
||||||
data: z.infer<Z>;
|
data: z.infer<Z> & {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
serverAction: (
|
serverAction: (
|
||||||
data: z.infer<Z> & {
|
data: z.infer<Z> & {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -119,8 +122,13 @@ export function UpdateModal<
|
|||||||
) => Promise<unknown>;
|
) => Promise<unknown>;
|
||||||
formSchema: Z;
|
formSchema: Z;
|
||||||
fieldConfig?: FieldConfig<z.infer<Z>>;
|
fieldConfig?: FieldConfig<z.infer<Z>>;
|
||||||
|
trigger?: React.ReactNode;
|
||||||
|
extraButtons?: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
// const [open, setOpen] = React.useState(false);
|
const [_open, _setOpen] = React.useState(false);
|
||||||
|
const open = props.open ?? _open;
|
||||||
|
const setOpen = props.setOpen ?? _setOpen;
|
||||||
|
|
||||||
const [values, setValues] = useState<Partial<z.infer<Z>>>({});
|
const [values, setValues] = useState<Partial<z.infer<Z>>>({});
|
||||||
const [isLoading, setIsLoading] = React.useState(false);
|
const [isLoading, setIsLoading] = React.useState(false);
|
||||||
|
|
||||||
@@ -129,10 +137,18 @@ export function UpdateModal<
|
|||||||
}, [props.data]);
|
}, [props.data]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={props.open} onOpenChange={props.setOpen}>
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
{/* <DialogTrigger asChild>
|
{props.trigger ?? (
|
||||||
<DropdownMenuItem>{props.title}</DropdownMenuItem>
|
<DialogTrigger
|
||||||
</DialogTrigger> */}
|
className="appearance-none hover:cursor-pointer"
|
||||||
|
asChild
|
||||||
|
onClick={() => {
|
||||||
|
setOpen(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.trigger}
|
||||||
|
</DialogTrigger>
|
||||||
|
)}
|
||||||
<DialogContent className={cn("sm:max-w-[425px]", props.dialogClassName)}>
|
<DialogContent className={cn("sm:max-w-[425px]", props.dialogClassName)}>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>{props.title}</DialogTitle>
|
<DialogTitle>{props.title}</DialogTitle>
|
||||||
@@ -152,13 +168,14 @@ export function UpdateModal<
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
props.setOpen(false);
|
setOpen(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end flex-wrap gap-2">
|
||||||
|
{props.extraButtons}
|
||||||
<AutoFormSubmit>
|
<AutoFormSubmit>
|
||||||
Save Changes
|
Save Changes
|
||||||
<span className="ml-2">{isLoading && <LoadingIcon />}</span>
|
{isLoading && <LoadingIcon />}
|
||||||
</AutoFormSubmit>
|
</AutoFormSubmit>
|
||||||
</div>
|
</div>
|
||||||
</AutoForm>
|
</AutoForm>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { getRelativeTime } from "../lib/getRelativeTime";
|
import { getRelativeTime } from "../lib/getRelativeTime";
|
||||||
import { InsertModal, UpdateModal } from "./InsertModal";
|
import { InsertModal, UpdateModal } from "./InsertModal";
|
||||||
import { callServerPromise } from "./callServerPromise";
|
import { callServerPromise } from "./callServerPromise";
|
||||||
|
import { LoadingIcon } from "@/components/LoadingIcon";
|
||||||
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";
|
||||||
@@ -107,8 +108,20 @@ export const columns: ColumnDef<Machine>[] = [
|
|||||||
{row.original.disabled && (
|
{row.original.disabled && (
|
||||||
<Badge variant="destructive">Disabled</Badge>
|
<Badge variant="destructive">Disabled</Badge>
|
||||||
)}
|
)}
|
||||||
|
{row.original.status == "building" && (
|
||||||
|
<Badge variant="amber" className="capitalize">
|
||||||
|
{row.original.status} <LoadingIcon />
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
{!row.original.disabled && row.original.status && (
|
{!row.original.disabled && row.original.status && (
|
||||||
<Badge variant="outline">{row.original.status}</Badge>
|
<Badge
|
||||||
|
variant={
|
||||||
|
row.original.status == "ready" ? "success" : "destructive"
|
||||||
|
}
|
||||||
|
className="capitalize"
|
||||||
|
>
|
||||||
|
{row.original.status}
|
||||||
|
</Badge>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
// </a>
|
// </a>
|
||||||
@@ -210,7 +223,7 @@ export const columns: ColumnDef<Machine>[] = [
|
|||||||
href={machine.endpoint.replace(
|
href={machine.endpoint.replace(
|
||||||
"comfyui-api",
|
"comfyui-api",
|
||||||
"comfyui-app"
|
"comfyui-app"
|
||||||
)}
|
)} rel="noreferrer"
|
||||||
>
|
>
|
||||||
Open ComfyUI
|
Open ComfyUI
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export default async function Main() {
|
|||||||
</Section.Announcement>
|
</Section.Announcement>
|
||||||
|
|
||||||
<Section.Title className="text-left">
|
<Section.Title className="text-left">
|
||||||
<span className="text-6xl md:text-7xl pb-2 inline-flex animate-background-shine bg-[linear-gradient(110deg,#1e293b,45%,#939393,55%,#1e293b)] bg-[length:250%_100%] bg-clip-text text-transparent">
|
<span className="text-5xl sm:text-6xl md:text-7xl pb-2 inline-flex animate-background-shine bg-[linear-gradient(110deg,#1e293b,45%,#939393,55%,#1e293b)] bg-[length:250%_100%] bg-clip-text text-transparent">
|
||||||
{meta.tagline}
|
{meta.tagline}
|
||||||
</span>
|
</span>
|
||||||
</Section.Title>
|
</Section.Title>
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ 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);
|
||||||
|
const [isSheetOpen, setSheetOpen] = useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsDesktop(_isDesktop);
|
setIsDesktop(_isDesktop);
|
||||||
}, [_isDesktop]);
|
}, [_isDesktop]);
|
||||||
@@ -36,18 +37,21 @@ export function Navbar() {
|
|||||||
<>
|
<>
|
||||||
<div className="flex flex-row items-center gap-4">
|
<div className="flex flex-row items-center gap-4">
|
||||||
{!isDesktop && (
|
{!isDesktop && (
|
||||||
<Sheet>
|
<Sheet open={isSheetOpen} onOpenChange={(open) => setSheetOpen(open)}>
|
||||||
<SheetTrigger asChild>
|
<SheetTrigger asChild>
|
||||||
<Button variant="ghost" className="w-8 h-8 p-2">
|
<button className="flex items-center justify-center w-8 h-8 p-2">
|
||||||
<Menu />
|
<Menu />
|
||||||
</Button>
|
</button>
|
||||||
</SheetTrigger>
|
</SheetTrigger>
|
||||||
<SheetContent side="left" className="flex flex-col gap-4">
|
<SheetContent side="left" className="flex flex-col gap-4">
|
||||||
<SheetHeader>
|
<SheetHeader>
|
||||||
<SheetTitle className="text-start">Comfy Deploy</SheetTitle>
|
<SheetTitle className="text-start">Comfy Deploy</SheetTitle>
|
||||||
</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"
|
||||||
|
closeSheet={() => setSheetOpen(false)}
|
||||||
|
/>
|
||||||
{/* <OrganizationSwitcher
|
{/* <OrganizationSwitcher
|
||||||
appearance={{
|
appearance={{
|
||||||
elements: {
|
elements: {
|
||||||
@@ -98,7 +102,7 @@ export function Navbar() {
|
|||||||
variant="outline"
|
variant="outline"
|
||||||
className="rounded-full aspect-square p-2"
|
className="rounded-full aspect-square p-2"
|
||||||
>
|
>
|
||||||
<a target="_blank" href="https://github.com/BennyKok/comfyui-deploy">
|
<a target="_blank" href="https://github.com/BennyKok/comfyui-deploy" rel="noreferrer">
|
||||||
<Github />
|
<Github />
|
||||||
</a>
|
</a>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -9,7 +9,13 @@ import { useRouter } from "next/navigation";
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useMediaQuery } from "usehooks-ts";
|
import { useMediaQuery } from "usehooks-ts";
|
||||||
|
|
||||||
export function NavbarMenu({ className }: { className?: string }) {
|
export function NavbarMenu({
|
||||||
|
className,
|
||||||
|
closeSheet,
|
||||||
|
}: {
|
||||||
|
className?: string;
|
||||||
|
closeSheet?: () => void;
|
||||||
|
}) {
|
||||||
const _isDesktop = useMediaQuery("(min-width: 1024px)");
|
const _isDesktop = useMediaQuery("(min-width: 1024px)");
|
||||||
const [isDesktop, setIsDesktop] = useState(true);
|
const [isDesktop, setIsDesktop] = useState(true);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -34,6 +40,10 @@ export function NavbarMenu({ className }: { className?: string }) {
|
|||||||
name: "API Keys",
|
name: "API Keys",
|
||||||
path: "/api-keys",
|
path: "/api-keys",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Examples",
|
||||||
|
path: "/examples"
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -42,9 +52,9 @@ export function NavbarMenu({ className }: { className?: string }) {
|
|||||||
{isDesktop && (
|
{isDesktop && (
|
||||||
<Tabs
|
<Tabs
|
||||||
defaultValue={pathname}
|
defaultValue={pathname}
|
||||||
className="w-[300px] flex pointer-events-auto"
|
className="w-fit flex pointer-events-auto"
|
||||||
>
|
>
|
||||||
<TabsList className="grid w-full grid-cols-3">
|
<TabsList className="w-full">
|
||||||
{pages.map((page) => (
|
{pages.map((page) => (
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
key={page.name}
|
key={page.name}
|
||||||
@@ -68,6 +78,9 @@ export function NavbarMenu({ className }: { className?: string }) {
|
|||||||
<Link
|
<Link
|
||||||
key={page.name}
|
key={page.name}
|
||||||
href={page.path}
|
href={page.path}
|
||||||
|
onClick={() => {
|
||||||
|
if (!!closeSheet) closeSheet();
|
||||||
|
}}
|
||||||
className="p-2 hover:bg-gray-100/20 hover:underline"
|
className="p-2 hover:bg-gray-100/20 hover:underline"
|
||||||
>
|
>
|
||||||
{page.name}
|
{page.name}
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
|
import {
|
||||||
|
Carousel,
|
||||||
|
CarouselContent,
|
||||||
|
CarouselItem,
|
||||||
|
CarouselNext,
|
||||||
|
CarouselPrevious,
|
||||||
|
type CarouselApi,
|
||||||
|
} from "@/components/ui/carousel";
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
export function OutputPreview() {
|
||||||
|
const [api, setApi] = React.useState<CarouselApi>();
|
||||||
|
const [current, setCurrent] = React.useState(0);
|
||||||
|
const [count, setCount] = React.useState(0);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!api) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCount(api.scrollSnapList().length);
|
||||||
|
setCurrent(api.selectedScrollSnap() + 1);
|
||||||
|
|
||||||
|
api.on("select", () => {
|
||||||
|
setCurrent(api.selectedScrollSnap() + 1);
|
||||||
|
});
|
||||||
|
}, [api]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Carousel setApi={setApi} className="w-full max-w-xs">
|
||||||
|
<CarouselContent>
|
||||||
|
{Array.from({ length: 5 }).map((_, index) => (
|
||||||
|
<CarouselItem key={index}>
|
||||||
|
<Card>
|
||||||
|
<CardContent className="flex aspect-square items-center justify-center p-6">
|
||||||
|
<span className="text-4xl font-semibold">{index + 1}</span>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</CarouselItem>
|
||||||
|
))}
|
||||||
|
</CarouselContent>
|
||||||
|
<CarouselPrevious />
|
||||||
|
<CarouselNext />
|
||||||
|
</Carousel>
|
||||||
|
<div className="py-2 text-center text-sm text-muted-foreground">
|
||||||
|
Slide {current} of {count}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -5,6 +5,20 @@ export async function OutputRender(props: {
|
|||||||
run_id: string;
|
run_id: string;
|
||||||
filename: string;
|
filename: string;
|
||||||
}) {
|
}) {
|
||||||
|
if (props.filename.endsWith(".mp4") || props.filename.endsWith(".webm")) {
|
||||||
|
const url = await getFileDownloadUrl(
|
||||||
|
`outputs/runs/${props.run_id}/${props.filename}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<video controls autoPlay className="w-[400px]">
|
||||||
|
<source src={url} type="video/mp4" />
|
||||||
|
<source src={url} type="video/webm" />
|
||||||
|
Your browser does not support the video tag.
|
||||||
|
</video>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
props.filename.endsWith(".png") ||
|
props.filename.endsWith(".png") ||
|
||||||
props.filename.endsWith(".gif") ||
|
props.filename.endsWith(".gif") ||
|
||||||
@@ -12,13 +26,13 @@ export async function OutputRender(props: {
|
|||||||
props.filename.endsWith(".jpeg")
|
props.filename.endsWith(".jpeg")
|
||||||
) {
|
) {
|
||||||
const url = await getFileDownloadUrl(
|
const url = await getFileDownloadUrl(
|
||||||
`outputs/runs/${props.run_id}/${props.filename}`
|
`outputs/runs/${props.run_id}/${props.filename}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
return <img className="max-w-[200px]" alt={props.filename} src={url} />;
|
return <img className="max-w-[200px]" alt={props.filename} src={url} />;
|
||||||
} else {
|
} else {
|
||||||
const url = await getFileDownloadUrl(
|
const url = await getFileDownloadUrl(
|
||||||
`outputs/runs/${props.run_id}/${props.filename}`
|
`outputs/runs/${props.run_id}/${props.filename}`,
|
||||||
);
|
);
|
||||||
// console.log(url);
|
// console.log(url);
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { LoadingIcon } from "@/components/LoadingIcon";
|
import { LoadingIcon } from "@/components/LoadingIcon";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { RefreshCcw } from "lucide-react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useEffect, useTransition } from "react";
|
import { useEffect, useTransition } from "react";
|
||||||
|
|
||||||
export function RouteRefresher(props: { interval: number }) {
|
export function RouteRefresher(props: {
|
||||||
|
interval: number;
|
||||||
|
autoRefresh: boolean;
|
||||||
|
}) {
|
||||||
const [isPending, startTransition] = useTransition();
|
const [isPending, startTransition] = useTransition();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!props.autoRefresh) return;
|
||||||
|
|
||||||
let timeout: NodeJS.Timeout;
|
let timeout: NodeJS.Timeout;
|
||||||
|
|
||||||
const refresh = () => {
|
const refresh = () => {
|
||||||
@@ -35,7 +42,24 @@ export function RouteRefresher(props: { interval: number }) {
|
|||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
window.removeEventListener("visibilitychange", handleVisibilityChange);
|
window.removeEventListener("visibilitychange", handleVisibilityChange);
|
||||||
};
|
};
|
||||||
}, [props.interval, router]);
|
}, [props.interval, router, props.autoRefresh]);
|
||||||
|
|
||||||
return <div>{isPending && <LoadingIcon />}</div>;
|
return (
|
||||||
|
<div>
|
||||||
|
{isPending && <LoadingIcon />}
|
||||||
|
{!isPending && !props.autoRefresh && (
|
||||||
|
<Button
|
||||||
|
className="p-0 h-min"
|
||||||
|
variant="ghost"
|
||||||
|
onClick={() => {
|
||||||
|
startTransition(() => {
|
||||||
|
router.refresh();
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RefreshCcw size={14} />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +1,74 @@
|
|||||||
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 {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogDescription,
|
DialogDescription,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
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 { getRelativeTime } from "@/lib/getRelativeTime";
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip";
|
||||||
|
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,
|
||||||
}: {
|
}: {
|
||||||
run: Awaited<ReturnType<typeof findAllRuns>>[0];
|
run: Awaited<ReturnType<typeof findAllRuns>>[0];
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Dialog>
|
<Dialog>
|
||||||
<DialogTrigger asChild className="appearance-none hover:cursor-pointer">
|
<DialogTrigger asChild className="appearance-none hover:cursor-pointer">
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell>{run.number}</TableCell>
|
<TableCell>{run.number}</TableCell>
|
||||||
<TableCell className="font-medium truncate">
|
<TableCell className="font-medium truncate">
|
||||||
{run.machine?.name}
|
{run.machine?.name}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="truncate">
|
<TableCell className="truncate">
|
||||||
{getRelativeTime(run.created_at)}
|
{getRelativeTime(run.created_at)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>{run.version?.version}</TableCell>
|
<TableCell>{run.version?.version}</TableCell>
|
||||||
<LiveStatus run={run} />
|
<TableCell>
|
||||||
</TableRow>
|
<Badge variant="outline" className="truncate">
|
||||||
</DialogTrigger>
|
{run.origin}
|
||||||
<DialogContent className="max-w-3xl">
|
</Badge>
|
||||||
<DialogHeader>
|
</TableCell>
|
||||||
<DialogTitle>Run outputs</DialogTitle>
|
<TableCell className="truncate">
|
||||||
<DialogDescription>
|
<Tooltip>
|
||||||
You can view your run's outputs here
|
<TooltipTrigger>{getDuration(run.duration)}</TooltipTrigger>
|
||||||
</DialogDescription>
|
<TooltipContent>
|
||||||
</DialogHeader>
|
<div>Cold start: {getDuration(run.cold_start_duration)}</div>
|
||||||
<div className="max-h-96 overflow-y-scroll">
|
<div>Run duration: {getDuration(run.run_duration)}</div>
|
||||||
<RunInputs run={run} />
|
</TooltipContent>
|
||||||
<Suspense>
|
</Tooltip>
|
||||||
<RunOutputs run_id={run.id} />
|
</TableCell>
|
||||||
</Suspense>
|
<LiveStatus run={run} />
|
||||||
</div>
|
</TableRow>
|
||||||
{/* <div className="max-h-96 overflow-y-scroll">{view}</div> */}
|
</DialogTrigger>
|
||||||
</DialogContent>
|
<DialogContent className="max-w-3xl">
|
||||||
</Dialog>
|
<DialogHeader>
|
||||||
);
|
<DialogTitle>Run outputs</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
You can view your run's outputs here
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<div className="max-h-96 overflow-y-scroll">
|
||||||
|
<RunInputs run={run} />
|
||||||
|
<Suspense>
|
||||||
|
<RunOutputs run_id={run.id} />
|
||||||
|
</Suspense>
|
||||||
|
</div>
|
||||||
|
{/* <div className="max-h-96 overflow-y-scroll">{view}</div> */}
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { plainInputsToZod } from "../lib/workflowVersionInputsToZod";
|
||||||
|
import { publicRunStore } from "./VersionSelect";
|
||||||
|
import { callServerPromise } from "./callServerPromise";
|
||||||
|
import { LoadingIcon } from "@/components/LoadingIcon";
|
||||||
|
import AutoForm, { AutoFormSubmit } from "@/components/ui/auto-form";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import type { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow";
|
||||||
|
import { createRun } from "@/server/createRun";
|
||||||
|
import { useAuth, useClerk } from "@clerk/nextjs";
|
||||||
|
import { Play } from "lucide-react";
|
||||||
|
import { useMemo, useState } from "react";
|
||||||
|
|
||||||
|
// For share page
|
||||||
|
export function RunWorkflowInline({
|
||||||
|
inputs,
|
||||||
|
workflow_version_id,
|
||||||
|
machine_id,
|
||||||
|
}: {
|
||||||
|
inputs: ReturnType<typeof getInputsFromWorkflow>;
|
||||||
|
workflow_version_id: string;
|
||||||
|
machine_id: string;
|
||||||
|
}) {
|
||||||
|
const [values, setValues] = useState<Record<string, string>>({});
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
|
const user = useAuth();
|
||||||
|
const clerk = useClerk();
|
||||||
|
|
||||||
|
const schema = useMemo(() => {
|
||||||
|
return plainInputsToZod(inputs);
|
||||||
|
}, [inputs]);
|
||||||
|
|
||||||
|
const {
|
||||||
|
setRunId,
|
||||||
|
loading,
|
||||||
|
setLoading: setLoading2,
|
||||||
|
setStatus,
|
||||||
|
} = publicRunStore();
|
||||||
|
|
||||||
|
const runWorkflow = async () => {
|
||||||
|
if (!user.isSignedIn) {
|
||||||
|
clerk.openSignIn({
|
||||||
|
redirectUrl: window.location.href,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(values);
|
||||||
|
|
||||||
|
const val = Object.keys(values).length > 0 ? values : undefined;
|
||||||
|
setLoading2(true);
|
||||||
|
setIsLoading(true);
|
||||||
|
setStatus("preparing");
|
||||||
|
try {
|
||||||
|
const origin = window.location.origin;
|
||||||
|
const a = await callServerPromise(
|
||||||
|
createRun({
|
||||||
|
origin,
|
||||||
|
workflow_version_id: workflow_version_id,
|
||||||
|
machine_id: machine_id,
|
||||||
|
inputs: val,
|
||||||
|
runOrigin: "public-share",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
if (a && !("error" in a)) {
|
||||||
|
setRunId(a.workflow_run_id);
|
||||||
|
} else {
|
||||||
|
setLoading2(false);
|
||||||
|
}
|
||||||
|
console.log(a);
|
||||||
|
setIsLoading(false);
|
||||||
|
} catch (error) {
|
||||||
|
setIsLoading(false);
|
||||||
|
setLoading2(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{schema && (
|
||||||
|
<AutoForm
|
||||||
|
formSchema={schema}
|
||||||
|
values={values}
|
||||||
|
onValuesChange={setValues}
|
||||||
|
onSubmit={runWorkflow}
|
||||||
|
className="px-1"
|
||||||
|
>
|
||||||
|
<div className="flex justify-end">
|
||||||
|
<AutoFormSubmit disabled={isLoading || loading}>
|
||||||
|
Run
|
||||||
|
{isLoading || loading ? <LoadingIcon /> : <Play size={14} />}
|
||||||
|
</AutoFormSubmit>
|
||||||
|
</div>
|
||||||
|
</AutoForm>
|
||||||
|
)}
|
||||||
|
{!schema && (
|
||||||
|
<Button
|
||||||
|
className="gap-2"
|
||||||
|
disabled={isLoading || loading}
|
||||||
|
onClick={runWorkflow}
|
||||||
|
>
|
||||||
|
Confirm {isLoading || loading ? <LoadingIcon /> : <Play size={14} />}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,10 +1,3 @@
|
|||||||
import {
|
|
||||||
findAllDeployments,
|
|
||||||
findAllRunsWithCounts,
|
|
||||||
} from "../server/findAllRuns";
|
|
||||||
import { DeploymentDisplay } from "./DeploymentDisplay";
|
|
||||||
import { PaginationControl } from "./PaginationControl";
|
|
||||||
import { RunDisplay } from "./RunDisplay";
|
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
@@ -14,6 +7,14 @@ import {
|
|||||||
TableRow,
|
TableRow,
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import { parseAsInteger } from "next-usequerystate";
|
import { parseAsInteger } from "next-usequerystate";
|
||||||
|
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);
|
||||||
@@ -32,44 +33,52 @@ 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="w-[100px]">Number</TableHead>
|
<TableHead className="truncate">Number</TableHead>
|
||||||
<TableHead className="">Machine</TableHead>
|
<TableHead className="truncate">Machine</TableHead>
|
||||||
<TableHead className="">Time</TableHead>
|
<TableHead className="truncate">Time</TableHead>
|
||||||
<TableHead className="w-[100px]">Version</TableHead>
|
<TableHead className="truncate">Version</TableHead>
|
||||||
<TableHead className="truncate">Live Status</TableHead>
|
<TableHead className="truncate">Origin</TableHead>
|
||||||
<TableHead className=" text-right">Status</TableHead>
|
<TableHead className="truncate">Duration</TableHead>
|
||||||
</TableRow>
|
<TableHead className="truncate">Live Status</TableHead>
|
||||||
</TableHeader>
|
<TableHead className="text-right">Status</TableHead>
|
||||||
<TableBody>
|
</TableRow>
|
||||||
{allRuns.map((run) => (
|
</TableHeader>
|
||||||
<RunDisplay run={run} key={run.id} />
|
<TableBody>
|
||||||
))}
|
{allRuns.map((run) => (
|
||||||
</TableBody>
|
<RunDisplay run={run} key={run.id} />
|
||||||
</Table>
|
))}
|
||||||
</div>
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</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 }) {
|
||||||
const allRuns = await findAllDeployments(props.workflow_id);
|
const allRuns = await findAllDeployments(props.workflow_id);
|
||||||
|
|
||||||
|
const headersList = headers();
|
||||||
|
const host = headersList.get("host") || "";
|
||||||
|
const protocol = headersList.get("x-forwarded-proto") || "";
|
||||||
|
const domain = `${protocol}://${host}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="overflow-auto h-fit w-full">
|
<div className="overflow-auto h-fit w-full">
|
||||||
<Table className="">
|
<Table className="">
|
||||||
<TableCaption>A list of your deployments</TableCaption>
|
<TableCaption>A list of your deployments</TableCaption>
|
||||||
<TableHeader className="bg-background top-0 sticky">
|
<TableHeader className="bg-background top-0 sticky">
|
||||||
@@ -82,7 +91,7 @@ export async function DeploymentsTable(props: { workflow_id: string }) {
|
|||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{allRuns.map((run) => (
|
{allRuns.map((run) => (
|
||||||
<DeploymentDisplay deployment={run} key={run.id} />
|
<DeploymentDisplay deployment={run} key={run.id} domain={domain} />
|
||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
|
|||||||
@@ -1,33 +1,37 @@
|
|||||||
import { Button, buttonVariants } from '@/components/ui/button';
|
|
||||||
type ButtonProps = React.ComponentProps<typeof Button>;
|
|
||||||
type LinkProps = React.ComponentProps<typeof Link>;
|
|
||||||
import { Card as BaseCard } from '@/components/ui/card';
|
|
||||||
type CardProps = React.ComponentProps<typeof BaseCard>;
|
|
||||||
import { Tabs, TabsTrigger as Tab, TabsList } from '@/components/ui/tabs';
|
|
||||||
type TabsProps = React.ComponentProps<typeof Tabs>;
|
|
||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
AccordionItem,
|
AccordionItem,
|
||||||
AccordionContent,
|
AccordionContent,
|
||||||
AccordionTrigger,
|
AccordionTrigger,
|
||||||
} from '@/components/ui/accordion';
|
} from "@/components/ui/accordion";
|
||||||
type AccordionProps = React.ComponentProps<typeof Accordion>;
|
import { Badge as Chip } from "@/components/ui/badge";
|
||||||
import { Badge as Chip } from '@/components/ui/badge';
|
import { Button, buttonVariants } from "@/components/ui/button";
|
||||||
type ChipProps = React.ComponentProps<typeof Chip>;
|
import { Card as BaseCard } from "@/components/ui/card";
|
||||||
|
import { Tabs, TabsTrigger as Tab, TabsList } from "@/components/ui/tabs";
|
||||||
import Link from 'next/link';
|
// import { PiCheckCircleDuotone } from 'react-icons/pi';
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { ChevronRight as MdChevronRight } from "lucide-react";
|
||||||
|
import { CheckCircle as PiCheckCircleDuotone } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
import type {
|
import type {
|
||||||
HTMLAttributeAnchorTarget,
|
HTMLAttributeAnchorTarget,
|
||||||
HTMLAttributes,
|
HTMLAttributes,
|
||||||
ReactNode,
|
ReactNode,
|
||||||
} from 'react';
|
} from "react";
|
||||||
import { twMerge } from 'tailwind-merge';
|
|
||||||
import { ChevronRight as MdChevronRight} from 'lucide-react'
|
|
||||||
// import { MdChevronRight } from 'react-icons/md';
|
// import { MdChevronRight } from 'react-icons/md';
|
||||||
import React from 'react';
|
import React from "react";
|
||||||
import { CheckCircle as PiCheckCircleDuotone } from 'lucide-react'
|
import { twMerge } from "tailwind-merge";
|
||||||
// import { PiCheckCircleDuotone } from 'react-icons/pi';
|
|
||||||
import { cn } from '@/lib/utils';
|
type ButtonProps = React.ComponentProps<typeof Button>;
|
||||||
|
type LinkProps = React.ComponentProps<typeof Link>;
|
||||||
|
|
||||||
|
type CardProps = React.ComponentProps<typeof BaseCard>;
|
||||||
|
|
||||||
|
type TabsProps = React.ComponentProps<typeof Tabs>;
|
||||||
|
|
||||||
|
type AccordionProps = React.ComponentProps<typeof Accordion>;
|
||||||
|
|
||||||
|
type ChipProps = React.ComponentProps<typeof Chip>;
|
||||||
|
|
||||||
function Section({
|
function Section({
|
||||||
className,
|
className,
|
||||||
@@ -41,8 +45,8 @@ function Section({
|
|||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'flex min-h-[400px] w-full max-w-6xl flex-col justify-center gap-2 rounded-lg px-10 py-10 md:px-20',
|
"flex min-h-[400px] w-full max-w-6xl flex-col justify-center gap-2 rounded-lg px-2 sm:px-10 py-10 md:px-20",
|
||||||
className,
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
@@ -64,12 +68,12 @@ function Title({
|
|||||||
<h1
|
<h1
|
||||||
{...props}
|
{...props}
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'text-center text-4xl font-bold md:text-6xl',
|
"text-center text-4xl font-bold md:text-6xl",
|
||||||
className,
|
className
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
textWrap: 'balance',
|
textWrap: "balance",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
@@ -86,12 +90,12 @@ function Subtitle({
|
|||||||
<h2
|
<h2
|
||||||
{...props}
|
{...props}
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'text text-center overflow-hidden text-ellipsis text-xl',
|
"text text-center overflow-hidden text-ellipsis text-xl",
|
||||||
className,
|
className
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
textWrap: 'balance',
|
textWrap: "balance",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
@@ -103,7 +107,7 @@ function Announcement({
|
|||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
href,
|
href,
|
||||||
target = '_blank',
|
target = "_blank",
|
||||||
...props
|
...props
|
||||||
}: ChipProps & {
|
}: ChipProps & {
|
||||||
href?: string; //string | UrlObject;
|
href?: string; //string | UrlObject;
|
||||||
@@ -112,8 +116,8 @@ function Announcement({
|
|||||||
return (
|
return (
|
||||||
<Chip
|
<Chip
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'w-fit group bg-foreground-50 text-center transition-colors hover:bg-gray-200',
|
"w-fit group bg-foreground-50 text-center transition-colors hover:bg-gray-200",
|
||||||
className,
|
className
|
||||||
)}
|
)}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
// href={href}
|
// href={href}
|
||||||
@@ -127,13 +131,13 @@ function Announcement({
|
|||||||
// }
|
// }
|
||||||
style={{
|
style={{
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
textWrap: 'balance',
|
textWrap: "balance",
|
||||||
}}
|
}}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<a href={href} target={target}>
|
<a href={href} target={target}>
|
||||||
{children}
|
{children}
|
||||||
</a>{' '}
|
</a>{" "}
|
||||||
<MdChevronRight
|
<MdChevronRight
|
||||||
size={20}
|
size={20}
|
||||||
className="pr-1 transition-transform group-hover:translate-x-[2px]"
|
className="pr-1 transition-transform group-hover:translate-x-[2px]"
|
||||||
@@ -143,14 +147,14 @@ function Announcement({
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ActionProps = ButtonProps & {
|
type ActionProps = ButtonProps & {
|
||||||
be: 'button';
|
be: "button";
|
||||||
hideArrow?: boolean;
|
hideArrow?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ActionLinkProps = LinkProps & {
|
type ActionLinkProps = LinkProps & {
|
||||||
be?: 'a';
|
be?: "a";
|
||||||
hideArrow?: boolean;
|
hideArrow?: boolean;
|
||||||
variant?: ButtonProps['variant'];
|
variant?: ButtonProps["variant"];
|
||||||
};
|
};
|
||||||
|
|
||||||
function PrimaryAction({
|
function PrimaryAction({
|
||||||
@@ -160,15 +164,15 @@ function PrimaryAction({
|
|||||||
hideArrow,
|
hideArrow,
|
||||||
...props
|
...props
|
||||||
}: ActionLinkProps | ActionProps) {
|
}: ActionLinkProps | ActionProps) {
|
||||||
if (props.be === 'button') {
|
if (props.be === "button") {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
className={cn(
|
className={cn(
|
||||||
buttonVariants({
|
buttonVariants({
|
||||||
variant: variant,
|
variant: variant,
|
||||||
}),
|
}),
|
||||||
'group',
|
"group",
|
||||||
className,
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
@@ -186,8 +190,8 @@ function PrimaryAction({
|
|||||||
buttonVariants({
|
buttonVariants({
|
||||||
variant: variant,
|
variant: variant,
|
||||||
}),
|
}),
|
||||||
'group',
|
"group",
|
||||||
className,
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
@@ -206,17 +210,17 @@ function SecondaryAction({
|
|||||||
hideArrow,
|
hideArrow,
|
||||||
...props
|
...props
|
||||||
}: ActionLinkProps | ActionProps) {
|
}: ActionLinkProps | ActionProps) {
|
||||||
if (props.be === 'button') {
|
if (props.be === "button") {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
className={cn(
|
className={cn(
|
||||||
buttonVariants({
|
buttonVariants({
|
||||||
variant: variant,
|
variant: variant,
|
||||||
}),
|
}),
|
||||||
'group',
|
"group",
|
||||||
className,
|
className
|
||||||
)}
|
)}
|
||||||
variant={'ghost'}
|
variant="ghost"
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
@@ -231,10 +235,10 @@ function SecondaryAction({
|
|||||||
<Link
|
<Link
|
||||||
className={cn(
|
className={cn(
|
||||||
buttonVariants({
|
buttonVariants({
|
||||||
variant: 'ghost',
|
variant: "ghost",
|
||||||
}),
|
}),
|
||||||
'group',
|
"group",
|
||||||
className,
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
@@ -249,31 +253,31 @@ function PricingCard({
|
|||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
}: Omit<CardProps, 'children'> & {
|
}: Omit<CardProps, "children"> & {
|
||||||
children:
|
children:
|
||||||
| ReactNode
|
| ReactNode
|
||||||
| ReactNode[]
|
| ReactNode[]
|
||||||
| ((pricingType: PricingType) => ReactNode | ReactNode[]);
|
| ((pricingType: PricingType) => ReactNode | ReactNode[]);
|
||||||
}) {
|
}) {
|
||||||
// const { pricingType } = usePricingContext();
|
// const { pricingType } = usePricingContext();
|
||||||
if (typeof children === 'function')
|
if (typeof children === "function")
|
||||||
children = (children('month') as React.ReactElement).props.children as
|
children = (children("month") as React.ReactElement).props.children as
|
||||||
| ReactNode
|
| ReactNode
|
||||||
| ReactNode[];
|
| ReactNode[];
|
||||||
|
|
||||||
// extract the title and subtitle from the children
|
// extract the title and subtitle from the children
|
||||||
// const cardTitleStyles =
|
// const cardTitleStyles =
|
||||||
const title = getChildComponent(children, Title, {
|
const title = getChildComponent(children, Title, {
|
||||||
className: 'text-2xl md:text-2xl text-start font-bold',
|
className: "text-2xl md:text-2xl text-start font-bold",
|
||||||
});
|
});
|
||||||
const subTitle = getChildComponent(children, Subtitle, {
|
const subTitle = getChildComponent(children, Subtitle, {
|
||||||
className: 'text-md text-start text-foreground-500 mt-4',
|
className: "text-md text-start text-foreground-500 mt-4",
|
||||||
});
|
});
|
||||||
const priceTags = getChildComponents(children, PriceTag, {
|
const priceTags = getChildComponents(children, PriceTag, {
|
||||||
className: 'text-4xl font-bold',
|
className: "text-4xl font-bold",
|
||||||
});
|
});
|
||||||
const primaryAction = getChildComponent(children, PrimaryAction, {
|
const primaryAction = getChildComponent(children, PrimaryAction, {
|
||||||
className: 'w-full',
|
className: "w-full",
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -281,8 +285,8 @@ function PricingCard({
|
|||||||
// shadow="sm"
|
// shadow="sm"
|
||||||
{...props}
|
{...props}
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'flex flex-col min-h-[400px] w-full max-w-full items-start justify-between gap-2 p-8 text-sm',
|
"flex flex-col min-h-[400px] w-full max-w-full items-start justify-between gap-2 p-8 text-sm",
|
||||||
className,
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
@@ -320,7 +324,7 @@ function PricingCard({
|
|||||||
// setPricingType: (pricingType: PricingType) => {},
|
// setPricingType: (pricingType: PricingType) => {},
|
||||||
// });
|
// });
|
||||||
|
|
||||||
const PricingTypeValue = ['month', 'year'] as const;
|
const PricingTypeValue = ["month", "year"] as const;
|
||||||
export type PricingType = (typeof PricingTypeValue)[number];
|
export type PricingType = (typeof PricingTypeValue)[number];
|
||||||
|
|
||||||
// // an helper function to useContext
|
// // an helper function to useContext
|
||||||
@@ -350,7 +354,7 @@ function PricingOption({ className, ...props }: TabsProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<Tabs
|
||||||
className={twMerge('w-fit', className)}
|
className={twMerge("w-fit", className)}
|
||||||
defaultValue="month"
|
defaultValue="month"
|
||||||
aria-label="Pricing Options"
|
aria-label="Pricing Options"
|
||||||
{...props}
|
{...props}
|
||||||
@@ -384,10 +388,10 @@ function PriceTag({
|
|||||||
pricingType,
|
pricingType,
|
||||||
...props
|
...props
|
||||||
}: HTMLAttributes<HTMLHeadingElement> & {
|
}: HTMLAttributes<HTMLHeadingElement> & {
|
||||||
pricingType?: 'month' | 'year' | string;
|
pricingType?: "month" | "year" | string;
|
||||||
}) {
|
}) {
|
||||||
// const { pricingType: currentPricingType } = usePricingContext();
|
// const { pricingType: currentPricingType } = usePricingContext();
|
||||||
let currentPricingType = 'month';
|
const currentPricingType = "month";
|
||||||
|
|
||||||
if (pricingType != undefined && currentPricingType !== pricingType)
|
if (pricingType != undefined && currentPricingType !== pricingType)
|
||||||
return <></>;
|
return <></>;
|
||||||
@@ -399,10 +403,10 @@ function Card({ className, children, ...props }: CardProps) {
|
|||||||
// extract the title and subtitle from the children
|
// extract the title and subtitle from the children
|
||||||
// const cardTitleStyles =
|
// const cardTitleStyles =
|
||||||
const title = getChildComponent(children, Title, {
|
const title = getChildComponent(children, Title, {
|
||||||
className: 'text-2xl md:text-2xl font-normal text-center',
|
className: "text-2xl md:text-2xl font-normal text-center",
|
||||||
});
|
});
|
||||||
const subTitle = getChildComponent(children, Subtitle, {
|
const subTitle = getChildComponent(children, Subtitle, {
|
||||||
className: 'text-md text-center',
|
className: "text-md text-center",
|
||||||
});
|
});
|
||||||
const image = getChildComponent(children, ImageArea);
|
const image = getChildComponent(children, ImageArea);
|
||||||
|
|
||||||
@@ -411,8 +415,8 @@ function Card({ className, children, ...props }: CardProps) {
|
|||||||
// shadow="sm"
|
// shadow="sm"
|
||||||
{...props}
|
{...props}
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'flex min-h-[280px] w-full max-w-full items-center justify-center gap-2 p-4 text-sm flex-col',
|
"flex min-h-[280px] w-full max-w-full items-center justify-center gap-2 p-4 text-sm flex-col",
|
||||||
className,
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{image}
|
{image}
|
||||||
@@ -431,7 +435,7 @@ function ImageArea({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
{...props}
|
{...props}
|
||||||
className={twMerge('aspect-square w-14 bg-foreground-300', className)}
|
className={twMerge("aspect-square w-14 bg-foreground-300", className)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
@@ -442,11 +446,11 @@ function ImageArea({
|
|||||||
function getChildComponent<T extends (...args: any[]) => React.JSX.Element>(
|
function getChildComponent<T extends (...args: any[]) => React.JSX.Element>(
|
||||||
children: React.ReactNode | React.ReactNode[],
|
children: React.ReactNode | React.ReactNode[],
|
||||||
type: T,
|
type: T,
|
||||||
propsOverride?: Partial<Parameters<T>[0]>,
|
propsOverride?: Partial<Parameters<T>[0]>
|
||||||
) {
|
) {
|
||||||
const childrenArr = React.Children.toArray(children);
|
const childrenArr = React.Children.toArray(children);
|
||||||
let child = childrenArr.find(
|
let child = childrenArr.find(
|
||||||
(child) => React.isValidElement(child) && child.type === type,
|
(child) => React.isValidElement(child) && child.type === type
|
||||||
) as React.ReactElement<
|
) as React.ReactElement<
|
||||||
Parameters<T>[0],
|
Parameters<T>[0],
|
||||||
string | React.JSXElementConstructor<any>
|
string | React.JSXElementConstructor<any>
|
||||||
@@ -466,12 +470,12 @@ function getChildComponent<T extends (...args: any[]) => React.JSX.Element>(
|
|||||||
function getChildComponents<T extends (...args: any[]) => React.JSX.Element>(
|
function getChildComponents<T extends (...args: any[]) => React.JSX.Element>(
|
||||||
children: React.ReactNode | React.ReactNode[],
|
children: React.ReactNode | React.ReactNode[],
|
||||||
type: T,
|
type: T,
|
||||||
propsOverride?: Partial<Parameters<T>[0]>,
|
propsOverride?: Partial<Parameters<T>[0]>
|
||||||
) {
|
) {
|
||||||
const childrenArr = React.Children.toArray(children);
|
const childrenArr = React.Children.toArray(children);
|
||||||
let child = (
|
const child = (
|
||||||
childrenArr.filter(
|
childrenArr.filter(
|
||||||
(child) => React.isValidElement(child) && child.type === type,
|
(child) => React.isValidElement(child) && child.type === type
|
||||||
) as React.ReactElement<
|
) as React.ReactElement<
|
||||||
Parameters<T>[0],
|
Parameters<T>[0],
|
||||||
string | React.JSXElementConstructor<any>
|
string | React.JSXElementConstructor<any>
|
||||||
@@ -492,10 +496,10 @@ function getChildComponents<T extends (...args: any[]) => React.JSX.Element>(
|
|||||||
|
|
||||||
function removeFromChildren(
|
function removeFromChildren(
|
||||||
children: React.ReactNode | React.ReactNode[],
|
children: React.ReactNode | React.ReactNode[],
|
||||||
types: any[],
|
types: any[]
|
||||||
): React.ReactNode[] {
|
): React.ReactNode[] {
|
||||||
return React.Children.toArray(children).filter(
|
return React.Children.toArray(children).filter(
|
||||||
(child) => React.isValidElement(child) && !types.includes(child.type),
|
(child) => React.isValidElement(child) && !types.includes(child.type)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,11 +512,11 @@ function FAQItem({
|
|||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode | React.ReactNode[];
|
children: React.ReactNode | React.ReactNode[];
|
||||||
'aria-label': string;
|
"aria-label": string;
|
||||||
title: string;
|
title: string;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<AccordionItem value={props['aria-label']}>
|
<AccordionItem value={props["aria-label"]}>
|
||||||
<AccordionTrigger>{props.title}</AccordionTrigger>
|
<AccordionTrigger>{props.title}</AccordionTrigger>
|
||||||
<AccordionContent>{children}</AccordionContent>
|
<AccordionContent>{children}</AccordionContent>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { ButtonAction } from "@/components/ButtonActionLoader";
|
||||||
|
import { UpdateModal } from "@/components/InsertModal";
|
||||||
|
import { LoadingPageWrapper } from "@/components/LoadingWrapper";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { publicShareDeployment } from "@/db/schema";
|
||||||
|
import {
|
||||||
|
findUserShareDeployment,
|
||||||
|
removePublicShareDeployment,
|
||||||
|
updateSharePageInfo,
|
||||||
|
} from "@/server/curdDeploments";
|
||||||
|
import { ExternalLink } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { useServerActionData } from "./useServerActionData";
|
||||||
|
|
||||||
|
export function SharePageSettings({
|
||||||
|
deployment_id,
|
||||||
|
}: {
|
||||||
|
deployment_id: string;
|
||||||
|
}) {
|
||||||
|
const {
|
||||||
|
data: deployment,
|
||||||
|
pending,
|
||||||
|
started,
|
||||||
|
} = useServerActionData(findUserShareDeployment, deployment_id);
|
||||||
|
|
||||||
|
const [_open, _setOpen] = useState(false);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
if (pending) return <LoadingPageWrapper className="h-full" tag="settings" />;
|
||||||
|
|
||||||
|
if (!deployment && started && !pending)
|
||||||
|
return (
|
||||||
|
<div className="h-full w-full flex items-center justify-center">
|
||||||
|
<p>Settings page not found.</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!deployment) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<UpdateModal
|
||||||
|
dialogClassName="sm:max-w-[600px]"
|
||||||
|
open={true}
|
||||||
|
setOpen={() => {
|
||||||
|
router.back();
|
||||||
|
}}
|
||||||
|
extraButtons={
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
asChild
|
||||||
|
className="gap-2 truncate"
|
||||||
|
variant="outline"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<ButtonAction
|
||||||
|
routerAction="back"
|
||||||
|
action={removePublicShareDeployment.bind(null, deployment.id)}
|
||||||
|
>
|
||||||
|
Remove
|
||||||
|
</ButtonAction>
|
||||||
|
</Button>
|
||||||
|
<Button asChild className="gap-2 truncate" type="button">
|
||||||
|
<Link href={`/share/${deployment.share_slug ?? deployment.id}`} target="_blank">
|
||||||
|
View Share Page <ExternalLink size={14} />
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
data={{
|
||||||
|
id: deployment.id,
|
||||||
|
description: deployment.description,
|
||||||
|
showcase_media: deployment.showcase_media ?? [],
|
||||||
|
}}
|
||||||
|
title="Share Page"
|
||||||
|
description="Edit share page details."
|
||||||
|
serverAction={updateSharePageInfo}
|
||||||
|
formSchema={publicShareDeployment}
|
||||||
|
fieldConfig={{
|
||||||
|
description: {
|
||||||
|
fieldType: "textarea",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,11 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import {
|
|
||||||
plainInputsToZod,
|
|
||||||
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";
|
||||||
@@ -42,20 +36,18 @@ import {
|
|||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import type { workflowAPINodeType } from "@/db/schema";
|
import type { showcaseMediaNullable, workflowAPINodeType } from "@/db/schema";
|
||||||
import type { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow";
|
|
||||||
import { checkStatus, createRun } from "@/server/createRun";
|
import { checkStatus, createRun } from "@/server/createRun";
|
||||||
import { createDeployments } from "@/server/curdDeploments";
|
import { createDeployments } from "@/server/curdDeploments";
|
||||||
import type { getMachines } from "@/server/curdMachine";
|
import type { getMachines } from "@/server/curdMachine";
|
||||||
import type { findFirstTableWithVersion } from "@/server/findFirstTableWithVersion";
|
import type { findFirstTableWithVersion } from "@/server/findFirstTableWithVersion";
|
||||||
import { useAuth, useClerk } from "@clerk/nextjs";
|
|
||||||
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";
|
||||||
@@ -63,6 +55,11 @@ 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,
|
||||||
@@ -127,12 +124,48 @@ export function MachineSelect({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function useSelectedMachine(machines: Awaited<ReturnType<typeof getMachines>>) {
|
type SelectedMachineStore = {
|
||||||
const a = useQueryState("machine", {
|
selectedMachine: string | undefined;
|
||||||
defaultValue: machines?.[0]?.id ?? "",
|
setSelectedMachine: (machine: string) => void;
|
||||||
});
|
};
|
||||||
|
|
||||||
return a;
|
export const selectedMachineStore = create<SelectedMachineStore>((set) => ({
|
||||||
|
selectedMachine: undefined,
|
||||||
|
setSelectedMachine: (machine) => set(() => ({ selectedMachine: machine })),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export function useSelectedMachine(
|
||||||
|
machines: Awaited<ReturnType<typeof getMachines>>,
|
||||||
|
): [string, (v: string) => void] {
|
||||||
|
const { selectedMachine, setSelectedMachine } = selectedMachineStore();
|
||||||
|
return [selectedMachine ?? machines?.[0]?.id ?? "", setSelectedMachine];
|
||||||
|
|
||||||
|
// const searchParams = useSearchParams();
|
||||||
|
// const pathname = usePathname();
|
||||||
|
// const router = useRouter();
|
||||||
|
|
||||||
|
// const createQueryString = useCallback(
|
||||||
|
// (name: string, value: string) => {
|
||||||
|
// const params = new URLSearchParams(searchParams.toString());
|
||||||
|
// params.set(name, value);
|
||||||
|
|
||||||
|
// return params.toString();
|
||||||
|
// },
|
||||||
|
// [searchParams],
|
||||||
|
// );
|
||||||
|
|
||||||
|
// return [
|
||||||
|
// searchParams.get("machine") ?? machines?.[0]?.id ?? "",
|
||||||
|
// (v: string) => {
|
||||||
|
// // window.history.pushState(
|
||||||
|
// // "new url",
|
||||||
|
// // "",
|
||||||
|
// // pathname + "?" + createQueryString("machine", v),
|
||||||
|
// // );
|
||||||
|
// // router.push(pathname + "?" + createQueryString("machine", v));
|
||||||
|
// router.replace(pathname + "?" + createQueryString("machine", v));
|
||||||
|
// },
|
||||||
|
// ];
|
||||||
}
|
}
|
||||||
|
|
||||||
type PublicRunStore = {
|
type PublicRunStore = {
|
||||||
@@ -147,7 +180,7 @@ type PublicRunStore = {
|
|||||||
setStatus: (status: string) => void;
|
setStatus: (status: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const publicRunStore = create<PublicRunStore>((set) => ({
|
export const publicRunStore = create<PublicRunStore>((set) => ({
|
||||||
image: "",
|
image: "",
|
||||||
loading: false,
|
loading: false,
|
||||||
runId: "",
|
runId: "",
|
||||||
@@ -159,7 +192,9 @@ const publicRunStore = create<PublicRunStore>((set) => ({
|
|||||||
setStatus: (status) => set({ status }),
|
setStatus: (status) => set({ status }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export function PublicRunOutputs() {
|
export function PublicRunOutputs(props: {
|
||||||
|
preview: z.infer<typeof showcaseMediaNullable>;
|
||||||
|
}) {
|
||||||
const { image, loading, runId, status, setStatus, setImage, setLoading } =
|
const { image, loading, runId, status, setStatus, setImage, setLoading } =
|
||||||
publicRunStore();
|
publicRunStore();
|
||||||
|
|
||||||
@@ -181,6 +216,15 @@ export function PublicRunOutputs() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border border-gray-200 w-full square h-[400px] rounded-lg relative">
|
<div className="border border-gray-200 w-full square h-[400px] rounded-lg relative">
|
||||||
|
{!loading && !image && props.preview && props.preview.length > 0 && (
|
||||||
|
<>
|
||||||
|
<img
|
||||||
|
className="w-full h-full object-contain"
|
||||||
|
src={props.preview[0]?.url}
|
||||||
|
alt="Generated image"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
{!loading && image && (
|
{!loading && image && (
|
||||||
<img
|
<img
|
||||||
className="w-full h-full object-contain"
|
className="w-full h-full object-contain"
|
||||||
@@ -198,105 +242,6 @@ export function PublicRunOutputs() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RunWorkflowInline({
|
|
||||||
inputs,
|
|
||||||
workflow_version_id,
|
|
||||||
machine_id,
|
|
||||||
}: {
|
|
||||||
inputs: ReturnType<typeof getInputsFromWorkflow>;
|
|
||||||
workflow_version_id: string;
|
|
||||||
machine_id: string;
|
|
||||||
}) {
|
|
||||||
const [values, setValues] = useState<Record<string, string>>({});
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
|
|
||||||
const user = useAuth();
|
|
||||||
const clerk = useClerk();
|
|
||||||
|
|
||||||
const schema = useMemo(() => {
|
|
||||||
return plainInputsToZod(inputs);
|
|
||||||
}, [inputs]);
|
|
||||||
|
|
||||||
const {
|
|
||||||
setRunId,
|
|
||||||
loading,
|
|
||||||
setLoading: setLoading2,
|
|
||||||
setStatus,
|
|
||||||
} = publicRunStore();
|
|
||||||
|
|
||||||
const runWorkflow = async () => {
|
|
||||||
console.log();
|
|
||||||
|
|
||||||
if (!user.isSignedIn) {
|
|
||||||
clerk.openSignIn({
|
|
||||||
redirectUrl: window.location.href,
|
|
||||||
});
|
|
||||||
console.log("hi");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log(values);
|
|
||||||
|
|
||||||
const val = Object.keys(values).length > 0 ? values : undefined;
|
|
||||||
setLoading2(true);
|
|
||||||
setIsLoading(true);
|
|
||||||
setStatus("preparing");
|
|
||||||
try {
|
|
||||||
const origin = window.location.origin;
|
|
||||||
const a = await callServerPromise(
|
|
||||||
createRun({
|
|
||||||
origin,
|
|
||||||
workflow_version_id: workflow_version_id,
|
|
||||||
machine_id: machine_id,
|
|
||||||
inputs: val,
|
|
||||||
isManualRun: true,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
if (a && !("error" in a)) {
|
|
||||||
setRunId(a.workflow_run_id);
|
|
||||||
} else {
|
|
||||||
setLoading2(false);
|
|
||||||
}
|
|
||||||
console.log(a);
|
|
||||||
setIsLoading(false);
|
|
||||||
} catch (error) {
|
|
||||||
setIsLoading(false);
|
|
||||||
setLoading2(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{schema && (
|
|
||||||
<AutoForm
|
|
||||||
formSchema={schema}
|
|
||||||
values={values}
|
|
||||||
onValuesChange={setValues}
|
|
||||||
onSubmit={runWorkflow}
|
|
||||||
className="px-1"
|
|
||||||
>
|
|
||||||
<div className="flex justify-end">
|
|
||||||
<AutoFormSubmit disabled={isLoading || loading}>
|
|
||||||
Run
|
|
||||||
<span className="ml-2">
|
|
||||||
{isLoading || loading ? <LoadingIcon /> : <Play size={14} />}
|
|
||||||
</span>
|
|
||||||
</AutoFormSubmit>
|
|
||||||
</div>
|
|
||||||
</AutoForm>
|
|
||||||
)}
|
|
||||||
{!schema && (
|
|
||||||
<Button
|
|
||||||
className="gap-2"
|
|
||||||
disabled={isLoading || loading}
|
|
||||||
onClick={runWorkflow}
|
|
||||||
>
|
|
||||||
Confirm {isLoading || loading ? <LoadingIcon /> : <Play size={14} />}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RunWorkflowButton({
|
export function RunWorkflowButton({
|
||||||
workflow,
|
workflow,
|
||||||
machines,
|
machines,
|
||||||
@@ -317,7 +262,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;
|
||||||
@@ -331,7 +276,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;
|
||||||
@@ -345,8 +290,8 @@ export function RunWorkflowButton({
|
|||||||
workflow_version_id,
|
workflow_version_id,
|
||||||
machine_id: machine,
|
machine_id: machine,
|
||||||
inputs: val,
|
inputs: val,
|
||||||
isManualRun: true,
|
runOrigin: "manual",
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
// console.log(res.json());
|
// console.log(res.json());
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@@ -385,9 +330,7 @@ export function RunWorkflowButton({
|
|||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<AutoFormSubmit>
|
<AutoFormSubmit>
|
||||||
Run
|
Run
|
||||||
<span className="ml-2">
|
{isLoading ? <LoadingIcon /> : <Play size={14} />}
|
||||||
{isLoading ? <LoadingIcon /> : <Play size={14} />}
|
|
||||||
</span>
|
|
||||||
</AutoFormSubmit>
|
</AutoFormSubmit>
|
||||||
</div>
|
</div>
|
||||||
</AutoForm>
|
</AutoForm>
|
||||||
@@ -417,7 +360,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>
|
||||||
@@ -437,8 +380,8 @@ export function CreateDeploymentButton({
|
|||||||
workflow.id,
|
workflow.id,
|
||||||
workflow_version_id,
|
workflow_version_id,
|
||||||
machine,
|
machine,
|
||||||
"production"
|
"production",
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}}
|
}}
|
||||||
@@ -455,8 +398,8 @@ export function CreateDeploymentButton({
|
|||||||
workflow.id,
|
workflow.id,
|
||||||
workflow_version_id,
|
workflow_version_id,
|
||||||
machine,
|
machine,
|
||||||
"staging"
|
"staging",
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}}
|
}}
|
||||||
@@ -468,7 +411,7 @@ export function CreateDeploymentButton({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CreateShareButton({
|
export function OpenEditButton({
|
||||||
workflow,
|
workflow,
|
||||||
machines,
|
machines,
|
||||||
}: {
|
}: {
|
||||||
@@ -480,40 +423,34 @@ export function CreateShareButton({
|
|||||||
...parseAsInteger,
|
...parseAsInteger,
|
||||||
});
|
});
|
||||||
const [machine] = useSelectedMachine(machines);
|
const [machine] = useSelectedMachine(machines);
|
||||||
|
|
||||||
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;
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
workflow_version_id &&
|
||||||
<DropdownMenuTrigger asChild>
|
machine && (
|
||||||
<Button className="gap-2" disabled={isLoading} variant="outline">
|
<Button
|
||||||
Share {isLoading ? <LoadingIcon /> : <Share size={14} />}
|
className="gap-2"
|
||||||
</Button>
|
onClick={async () => {
|
||||||
</DropdownMenuTrigger>
|
setIsLoading(true);
|
||||||
<DropdownMenuContent className="w-56">
|
const url = await callServerPromise(
|
||||||
<DropdownMenuItem
|
editWorkflowOnMachine(workflow_version_id, machine),
|
||||||
onClick={async () => {
|
);
|
||||||
if (!workflow_version_id) return;
|
if (url && typeof url !== "object") {
|
||||||
|
window.open(url, "_blank");
|
||||||
setIsLoading(true);
|
} else if (url && typeof url === "object" && url.error) {
|
||||||
await callServerPromise(
|
console.error(url.error);
|
||||||
createDeployments(
|
}
|
||||||
workflow.id,
|
setIsLoading(false);
|
||||||
workflow_version_id,
|
}}
|
||||||
machine,
|
// asChild
|
||||||
"public-share"
|
variant="outline"
|
||||||
)
|
>
|
||||||
);
|
Edit {isLoading ? <LoadingIcon /> : <Edit size={14} />}
|
||||||
setIsLoading(false);
|
</Button>
|
||||||
}}
|
)
|
||||||
>
|
|
||||||
Public
|
|
||||||
</DropdownMenuItem>
|
|
||||||
</DropdownMenuContent>
|
|
||||||
</DropdownMenu>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,7 +464,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>
|
||||||
@@ -551,7 +488,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");
|
||||||
}}
|
}}
|
||||||
@@ -561,7 +498,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");
|
||||||
}}
|
}}
|
||||||
@@ -575,7 +512,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);
|
||||||
|
|
||||||
@@ -601,7 +538,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(() => {
|
||||||
@@ -611,7 +548,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;
|
||||||
@@ -622,7 +559,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;
|
||||||
})
|
})
|
||||||
@@ -652,7 +589,7 @@ export function ViewWorkflowDetailsButton({
|
|||||||
node: z.infer<typeof workflowAPINodeType>[];
|
node: z.infer<typeof workflowAPINodeType>[];
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
>
|
>,
|
||||||
);
|
);
|
||||||
|
|
||||||
// console.log(groupedByAuxName);
|
// console.log(groupedByAuxName);
|
||||||
@@ -694,6 +631,7 @@ 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
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { getRelativeTime } from "../lib/getRelativeTime";
|
import { getRelativeTime } from "../lib/getRelativeTime";
|
||||||
|
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 {
|
import {
|
||||||
@@ -20,6 +21,7 @@ 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 {
|
import type {
|
||||||
ColumnDef,
|
ColumnDef,
|
||||||
@@ -38,14 +40,11 @@ import {
|
|||||||
import { ArrowUpDown, MoreHorizontal } from "lucide-react";
|
import { ArrowUpDown, MoreHorizontal } from "lucide-react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
export type Payment = {
|
export type WorkflowItemList = NonNullable<
|
||||||
id: string;
|
Awaited<ReturnType<typeof getAllUserWorkflow>>
|
||||||
amount: number;
|
>[0];
|
||||||
date: Date;
|
|
||||||
email: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const columns: ColumnDef<Payment>[] = [
|
export const columns: ColumnDef<WorkflowItemList>[] = [
|
||||||
{
|
{
|
||||||
accessorKey: "id",
|
accessorKey: "id",
|
||||||
id: "select",
|
id: "select",
|
||||||
@@ -70,7 +69,7 @@ export const columns: ColumnDef<Payment>[] = [
|
|||||||
enableHiding: false,
|
enableHiding: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "email",
|
accessorKey: "name",
|
||||||
header: ({ column }) => {
|
header: ({ column }) => {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
@@ -83,27 +82,35 @@ export const columns: ColumnDef<Payment>[] = [
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
|
const workflow = row.original;
|
||||||
return (
|
return (
|
||||||
<a className="hover:underline" href={`/workflows/${row.original.id}`}>
|
<a
|
||||||
{row.getValue("email")}
|
className="hover:underline flex gap-2"
|
||||||
|
href={`/workflows/${workflow.id}`}
|
||||||
|
>
|
||||||
|
<span className="truncate max-w-[200px]">{row.original.name}</span>
|
||||||
|
|
||||||
|
<Badge variant="default">v{row.original.versions[0]?.version}</Badge>
|
||||||
|
{workflow.deployments?.[0] && <Badge variant="success">Public</Badge>}
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
accessorKey: "amount",
|
accessorKey: "creator",
|
||||||
header: () => <div className="text-left">Version</div>,
|
header: ({ column }) => {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className="flex items-center hover:underline"
|
||||||
|
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||||
|
>
|
||||||
|
Creator
|
||||||
|
<ArrowUpDown className="ml-2 h-4 w-4" />
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
},
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const amount = parseFloat(row.getValue("amount"));
|
return <Badge variant="cyan">{row.original.user.name}</Badge>;
|
||||||
|
|
||||||
// Format the amount as a dollar amount
|
|
||||||
// const formatted = new Intl.NumberFormat("en-US", {
|
|
||||||
// style: "currency",
|
|
||||||
// currency: "USD",
|
|
||||||
// }).format(amount);
|
|
||||||
|
|
||||||
return <div className="text-left font-medium">{amount}</div>;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -113,7 +120,7 @@ export const columns: ColumnDef<Payment>[] = [
|
|||||||
header: ({ column }) => {
|
header: ({ column }) => {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
className="w-full flex items-center justify-end hover:underline"
|
className="w-full flex items-center justify-end hover:underline truncate"
|
||||||
// variant="ghost"
|
// variant="ghost"
|
||||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||||
>
|
>
|
||||||
@@ -123,8 +130,8 @@ export const columns: ColumnDef<Payment>[] = [
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<div className="w-full capitalize text-right">
|
<div className="w-full capitalize text-right truncate">
|
||||||
{getRelativeTime(row.original.date)}
|
{getRelativeTime(row.original.updated_at)}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -148,14 +155,10 @@ export const columns: ColumnDef<Payment>[] = [
|
|||||||
className="text-destructive"
|
className="text-destructive"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
deleteWorkflow(workflow.id);
|
deleteWorkflow(workflow.id);
|
||||||
// navigator.clipboard.writeText(payment.id)
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Delete Workflow
|
Delete Workflow
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
{/* <DropdownMenuSeparator />
|
|
||||||
<DropdownMenuItem>View customer</DropdownMenuItem>
|
|
||||||
<DropdownMenuItem>View payment details</DropdownMenuItem> */}
|
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
);
|
);
|
||||||
@@ -163,10 +166,10 @@ export const columns: ColumnDef<Payment>[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export function WorkflowList({ data }: { data: Payment[] }) {
|
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>({});
|
||||||
@@ -196,38 +199,12 @@ export function WorkflowList({ data }: { data: Payment[] }) {
|
|||||||
<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("email")?.getFilterValue() as string) ?? ""}
|
value={(table.getColumn("name")?.getFilterValue() as string) ?? ""}
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
table.getColumn("email")?.setFilterValue(event.target.value)
|
table.getColumn("name")?.setFilterValue(event.target.value)
|
||||||
}
|
}
|
||||||
className="max-w-sm"
|
className="max-w-sm"
|
||||||
/>
|
/>
|
||||||
{/* <DropdownMenu>
|
|
||||||
<DropdownMenuTrigger asChild>
|
|
||||||
<Button variant="outline" className="ml-auto">
|
|
||||||
Columns <ChevronDown className="ml-2 h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
</DropdownMenuTrigger>
|
|
||||||
<DropdownMenuContent align="end">
|
|
||||||
{table
|
|
||||||
.getAllColumns()
|
|
||||||
.filter((column) => column.getCanHide())
|
|
||||||
.map((column) => {
|
|
||||||
return (
|
|
||||||
<DropdownMenuCheckboxItem
|
|
||||||
key={column.id}
|
|
||||||
className="capitalize"
|
|
||||||
checked={column.getIsVisible()}
|
|
||||||
onCheckedChange={(value) =>
|
|
||||||
column.toggleVisibility(!!value)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{column.id}
|
|
||||||
</DropdownMenuCheckboxItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</DropdownMenuContent>
|
|
||||||
</DropdownMenu> */}
|
|
||||||
</div>
|
</div>
|
||||||
<ScrollArea className="h-full w-full rounded-md border">
|
<ScrollArea className="h-full w-full rounded-md border">
|
||||||
<Table>
|
<Table>
|
||||||
@@ -241,7 +218,7 @@ export function WorkflowList({ data }: { data: Payment[] }) {
|
|||||||
? null
|
? null
|
||||||
: flexRender(
|
: flexRender(
|
||||||
header.column.columnDef.header,
|
header.column.columnDef.header,
|
||||||
header.getContext()
|
header.getContext(),
|
||||||
)}
|
)}
|
||||||
</TableHead>
|
</TableHead>
|
||||||
);
|
);
|
||||||
@@ -260,7 +237,7 @@ export function WorkflowList({ data }: { data: Payment[] }) {
|
|||||||
<TableCell key={cell.id}>
|
<TableCell key={cell.id}>
|
||||||
{flexRender(
|
{flexRender(
|
||||||
cell.column.columnDef.cell,
|
cell.column.columnDef.cell,
|
||||||
cell.getContext()
|
cell.getContext(),
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ export const customInputNodes: Record<string, string> = {
|
|||||||
ComfyUIDeployExternalNumber: "float",
|
ComfyUIDeployExternalNumber: "float",
|
||||||
ComfyUIDeployExternalNumberInt: "integer",
|
ComfyUIDeployExternalNumberInt: "integer",
|
||||||
ComfyUIDeployExternalLora: "string - (public lora download url)",
|
ComfyUIDeployExternalLora: "string - (public lora download url)",
|
||||||
|
ComfyUIDeployExternalCheckpoint: "string - (public checkpoints download url)",
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
// Error components must be Client Components
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
export default function ErrorPage({
|
||||||
|
error,
|
||||||
|
reset,
|
||||||
|
}: {
|
||||||
|
error: Error & { digest?: string };
|
||||||
|
reset: () => void;
|
||||||
|
}) {
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(error.message);
|
||||||
|
}, [error]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="border rounded-2xl flex flex-col w-full h-full gap-20 justify-center items-center text-xs">
|
||||||
|
<div className="max-w-xl w-full">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>
|
||||||
|
<div className="text-xl">Unexpected error.</div>
|
||||||
|
</CardTitle>
|
||||||
|
<CardDescription className="flex flex-col gap-4">
|
||||||
|
<div className="text-sm">Error: {error.message}</div>
|
||||||
|
<div className="flex w-full justify-end">
|
||||||
|
<Button
|
||||||
|
className="w-fit"
|
||||||
|
onClick={() => {
|
||||||
|
window.location.reload();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Refresh Page
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ErrorFullPage({
|
||||||
|
error,
|
||||||
|
reset,
|
||||||
|
}: {
|
||||||
|
error: Error & { digest?: string };
|
||||||
|
reset: () => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"w-full py-4 flex justify-center items-center gap-2 text-sm h-full"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<ErrorPage error={error} reset={reset} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -69,7 +69,7 @@ const FeedbackThanks = forwardRef<React.ElementRef<'div'>>(
|
|||||||
)
|
)
|
||||||
|
|
||||||
export function Feedback() {
|
export function Feedback() {
|
||||||
let [submitted, setSubmitted] = useState(false)
|
const [submitted, setSubmitted] = useState(false)
|
||||||
|
|
||||||
function onSubmit(event: React.FormEvent<HTMLFormElement>) {
|
function onSubmit(event: React.FormEvent<HTMLFormElement>) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export function Prose<T extends React.ElementType = 'div'>({
|
|||||||
as?: T
|
as?: T
|
||||||
className?: string
|
className?: string
|
||||||
}) {
|
}) {
|
||||||
let Component = as ?? 'div'
|
const Component = as ?? 'div'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Component
|
<Component
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ function MoonIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function ThemeToggle() {
|
export function ThemeToggle() {
|
||||||
let { resolvedTheme, setTheme } = useTheme()
|
const { resolvedTheme, setTheme } = useTheme()
|
||||||
let otherTheme = resolvedTheme === 'dark' ? 'light' : 'dark'
|
const otherTheme = resolvedTheme === 'dark' ? 'light' : 'dark'
|
||||||
let [mounted, setMounted] = useState(false)
|
const [mounted, setMounted] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMounted(true)
|
setMounted(true)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export function AutoFormSubmit({
|
|||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Button type="submit" disabled={disabled}>
|
<Button type="submit" disabled={disabled} className="flex gap-2">
|
||||||
{children ?? "Submit"}
|
{children ?? "Submit"}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { DefaultValues } from "react-hook-form";
|
import type { DefaultValues } from "react-hook-form";
|
||||||
import { z } from "zod";
|
import type { z } from "zod";
|
||||||
|
|
||||||
// TODO: This should support recursive ZodEffects but TypeScript doesn't allow circular type definitions.
|
// TODO: This should support recursive ZodEffects but TypeScript doesn't allow circular type definitions.
|
||||||
export type ZodObjectOrWrapped =
|
export type ZodObjectOrWrapped =
|
||||||
@@ -21,7 +21,7 @@ export function beautifyObjectName(string: string) {
|
|||||||
* This will unpack optionals, refinements, etc.
|
* This will unpack optionals, refinements, etc.
|
||||||
*/
|
*/
|
||||||
export function getBaseSchema<
|
export function getBaseSchema<
|
||||||
ChildType extends z.ZodAny | z.AnyZodObject = z.ZodAny,
|
ChildType extends z.ZodAny | z.AnyZodObject = z.ZodAny
|
||||||
>(schema: ChildType | z.ZodEffects<ChildType>): ChildType {
|
>(schema: ChildType | z.ZodEffects<ChildType>): ChildType {
|
||||||
if ("innerType" in schema._def) {
|
if ("innerType" in schema._def) {
|
||||||
return getBaseSchema(schema._def.innerType as ChildType);
|
return getBaseSchema(schema._def.innerType as ChildType);
|
||||||
@@ -54,12 +54,12 @@ export function getDefaultValueInZodStack(schema: z.ZodAny): any {
|
|||||||
|
|
||||||
if ("innerType" in typedSchema._def) {
|
if ("innerType" in typedSchema._def) {
|
||||||
return getDefaultValueInZodStack(
|
return getDefaultValueInZodStack(
|
||||||
typedSchema._def.innerType as unknown as z.ZodAny,
|
typedSchema._def.innerType as unknown as z.ZodAny
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ("schema" in typedSchema._def) {
|
if ("schema" in typedSchema._def) {
|
||||||
return getDefaultValueInZodStack(
|
return getDefaultValueInZodStack(
|
||||||
(typedSchema._def as any).schema as z.ZodAny,
|
(typedSchema._def as any).schema as z.ZodAny
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -69,7 +69,7 @@ export function getDefaultValueInZodStack(schema: z.ZodAny): any {
|
|||||||
* Get all default values from a Zod schema.
|
* Get all default values from a Zod schema.
|
||||||
*/
|
*/
|
||||||
export function getDefaultValues<Schema extends z.ZodObject<any, any>>(
|
export function getDefaultValues<Schema extends z.ZodObject<any, any>>(
|
||||||
schema: Schema,
|
schema: Schema
|
||||||
) {
|
) {
|
||||||
const { shape } = schema;
|
const { shape } = schema;
|
||||||
type DefaultValuesType = DefaultValues<Partial<z.infer<Schema>>>;
|
type DefaultValuesType = DefaultValues<Partial<z.infer<Schema>>>;
|
||||||
@@ -80,7 +80,7 @@ export function getDefaultValues<Schema extends z.ZodObject<any, any>>(
|
|||||||
|
|
||||||
if (getBaseType(item) === "ZodObject") {
|
if (getBaseType(item) === "ZodObject") {
|
||||||
const defaultItems = getDefaultValues(
|
const defaultItems = getDefaultValues(
|
||||||
getBaseSchema(item) as unknown as z.ZodObject<any, any>,
|
getBaseSchema(item) as unknown as z.ZodObject<any, any>
|
||||||
);
|
);
|
||||||
for (const defaultItemKey of Object.keys(defaultItems)) {
|
for (const defaultItemKey of Object.keys(defaultItems)) {
|
||||||
const pathKey = `${key}.${defaultItemKey}` as keyof DefaultValuesType;
|
const pathKey = `${key}.${defaultItemKey}` as keyof DefaultValuesType;
|
||||||
@@ -98,7 +98,7 @@ export function getDefaultValues<Schema extends z.ZodObject<any, any>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getObjectFormSchema(
|
export function getObjectFormSchema(
|
||||||
schema: ZodObjectOrWrapped,
|
schema: ZodObjectOrWrapped
|
||||||
): z.ZodObject<any, any> {
|
): z.ZodObject<any, any> {
|
||||||
if (schema._def.typeName === "ZodEffects") {
|
if (schema._def.typeName === "ZodEffects") {
|
||||||
const typedSchema = schema as z.ZodEffects<z.ZodObject<any, any>>;
|
const typedSchema = schema as z.ZodEffects<z.ZodObject<any, any>>;
|
||||||
@@ -116,7 +116,7 @@ export function zodToHtmlInputProps(
|
|||||||
| z.ZodNumber
|
| z.ZodNumber
|
||||||
| z.ZodString
|
| z.ZodString
|
||||||
| z.ZodOptional<z.ZodNumber | z.ZodString>
|
| z.ZodOptional<z.ZodNumber | z.ZodString>
|
||||||
| any,
|
| any
|
||||||
): React.InputHTMLAttributes<HTMLInputElement> {
|
): React.InputHTMLAttributes<HTMLInputElement> {
|
||||||
if (["ZodOptional", "ZodNullable"].includes(schema._def.typeName)) {
|
if (["ZodOptional", "ZodNullable"].includes(schema._def.typeName)) {
|
||||||
const typedSchema = schema as z.ZodOptional<z.ZodNumber | z.ZodString>;
|
const typedSchema = schema as z.ZodOptional<z.ZodNumber | z.ZodString>;
|
||||||
@@ -128,9 +128,10 @@ export function zodToHtmlInputProps(
|
|||||||
|
|
||||||
const typedSchema = schema as z.ZodNumber | z.ZodString;
|
const typedSchema = schema as z.ZodNumber | z.ZodString;
|
||||||
|
|
||||||
if (!("checks" in typedSchema._def)) return {
|
if (!("checks" in typedSchema._def))
|
||||||
required: true
|
return {
|
||||||
};
|
required: true,
|
||||||
|
};
|
||||||
|
|
||||||
const { checks } = typedSchema._def;
|
const { checks } = typedSchema._def;
|
||||||
const inputProps: React.InputHTMLAttributes<HTMLInputElement> = {
|
const inputProps: React.InputHTMLAttributes<HTMLInputElement> = {
|
||||||
|
|||||||
@@ -2,20 +2,47 @@ import { cn } from "@/lib/utils";
|
|||||||
import { cva, type VariantProps } from "class-variance-authority";
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
|
const colors = {
|
||||||
|
red: "bg-red-500/15 text-red-700 group-data-[hover]:bg-red-500/25 dark:bg-red-500/10 dark:text-red-400 dark:group-data-[hover]:bg-red-500/20",
|
||||||
|
orange:
|
||||||
|
"bg-orange-500/15 text-orange-700 group-data-[hover]:bg-orange-500/25 dark:bg-orange-500/10 dark:text-orange-400 dark:group-data-[hover]:bg-orange-500/20",
|
||||||
|
amber:
|
||||||
|
"bg-amber-400/20 text-amber-700 group-data-[hover]:bg-amber-400/30 dark:bg-amber-400/10 dark:text-amber-400 dark:group-data-[hover]:bg-amber-400/15",
|
||||||
|
yellow:
|
||||||
|
"bg-yellow-400/20 text-yellow-700 group-data-[hover]:bg-yellow-400/30 dark:bg-yellow-400/10 dark:text-yellow-300 dark:group-data-[hover]:bg-yellow-400/15",
|
||||||
|
lime: "bg-lime-400/20 text-lime-700 group-data-[hover]:bg-lime-400/30 dark:bg-lime-400/10 dark:text-lime-300 dark:group-data-[hover]:bg-lime-400/15",
|
||||||
|
green:
|
||||||
|
"bg-green-500/15 text-green-700 group-data-[hover]:bg-green-500/25 dark:bg-green-500/10 dark:text-green-400 dark:group-data-[hover]:bg-green-500/20",
|
||||||
|
emerald:
|
||||||
|
"bg-emerald-500/15 text-emerald-700 group-data-[hover]:bg-emerald-500/25 dark:bg-emerald-500/10 dark:text-emerald-400 dark:group-data-[hover]:bg-emerald-500/20",
|
||||||
|
teal: "bg-teal-500/15 text-teal-700 group-data-[hover]:bg-teal-500/25 dark:bg-teal-500/10 dark:text-teal-300 dark:group-data-[hover]:bg-teal-500/20",
|
||||||
|
cyan: "bg-cyan-400/20 text-cyan-700 group-data-[hover]:bg-cyan-400/30 dark:bg-cyan-400/10 dark:text-cyan-300 dark:group-data-[hover]:bg-cyan-400/15",
|
||||||
|
sky: "bg-sky-500/15 text-sky-700 group-data-[hover]:bg-sky-500/25 dark:bg-sky-500/10 dark:text-sky-300 dark:group-data-[hover]:bg-sky-500/20",
|
||||||
|
blue: "bg-blue-500/15 text-blue-700 group-data-[hover]:bg-blue-500/25 dark:text-blue-400 dark:group-data-[hover]:bg-blue-500/25",
|
||||||
|
indigo:
|
||||||
|
"bg-indigo-500/15 text-indigo-700 group-data-[hover]:bg-indigo-500/25 dark:text-indigo-400 dark:group-data-[hover]:bg-indigo-500/20",
|
||||||
|
violet:
|
||||||
|
"bg-violet-500/15 text-violet-700 group-data-[hover]:bg-violet-500/25 dark:text-violet-400 dark:group-data-[hover]:bg-violet-500/20",
|
||||||
|
purple:
|
||||||
|
"bg-purple-500/15 text-purple-700 group-data-[hover]:bg-purple-500/25 dark:text-purple-400 dark:group-data-[hover]:bg-purple-500/20",
|
||||||
|
fuchsia:
|
||||||
|
"bg-fuchsia-400/15 text-fuchsia-700 group-data-[hover]:bg-fuchsia-400/25 dark:bg-fuchsia-400/10 dark:text-fuchsia-400 dark:group-data-[hover]:bg-fuchsia-400/20",
|
||||||
|
pink: "bg-pink-400/15 text-pink-700 group-data-[hover]:bg-pink-400/25 dark:bg-pink-400/10 dark:text-pink-400 dark:group-data-[hover]:bg-pink-400/20",
|
||||||
|
rose: "bg-rose-400/15 text-rose-700 group-data-[hover]:bg-rose-400/25 dark:bg-rose-400/10 dark:text-rose-400 dark:group-data-[hover]:bg-rose-400/20",
|
||||||
|
zinc: "bg-zinc-600/10 text-zinc-700 group-data-[hover]:bg-zinc-600/20 dark:bg-white/5 dark:text-zinc-400 dark:group-data-[hover]:bg-white/10",
|
||||||
|
};
|
||||||
|
|
||||||
const badgeVariants = cva(
|
const badgeVariants = cva(
|
||||||
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
"inline-flex items-center gap-x-1.5 rounded-md px-2 py-0.5 text-sm/5 font-medium sm:text-xs/5 forced-colors:outline",
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default:
|
default: colors["zinc"],
|
||||||
"border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
|
secondary: colors["zinc"],
|
||||||
secondary:
|
success: colors["green"],
|
||||||
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
destructive: colors["red"],
|
||||||
success:
|
outline: "text-foreground border",
|
||||||
"border-transparent bg-green-200 text-secondary-foreground hover:bg-green-200/80",
|
...colors,
|
||||||
destructive:
|
|
||||||
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
||||||
outline: "text-foreground",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
|
|||||||
@@ -3,34 +3,201 @@ import { Slot } from "@radix-ui/react-slot";
|
|||||||
import { cva, type VariantProps } from "class-variance-authority";
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
const buttonVariants = cva(
|
const styles = {
|
||||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
base: [
|
||||||
{
|
// Base
|
||||||
variants: {
|
"relative isolate inline-flex items-center justify-center gap-x-2 rounded-lg border text-base/6 font-semibold",
|
||||||
variant: {
|
|
||||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
// Sizing
|
||||||
destructive:
|
"px-[calc(theme(spacing.3)-1px)] py-[calc(theme(spacing[1.5])-1px)] text-sm/6",
|
||||||
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
||||||
outline:
|
// Focus
|
||||||
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
"focus:outline-none data-[focus]:outline data-[focus]:outline-2 data-[focus]:outline-offset-2 data-[focus]:outline-blue-500",
|
||||||
secondary:
|
|
||||||
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
// Disabled
|
||||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
"data-[disabled]:opacity-50",
|
||||||
link: "text-primary underline-offset-4 hover:underline",
|
|
||||||
},
|
// Icon
|
||||||
size: {
|
"[&>[data-slot=icon]]:-mx-0.5 [&>[data-slot=icon]]:my-0.5 [&>[data-slot=icon]]:size-5 [&>[data-slot=icon]]:shrink-0 [&>[data-slot=icon]]:text-[--btn-icon] [&>[data-slot=icon]]:sm:my-1 [&>[data-slot=icon]]:sm:size-4 forced-colors:[--btn-icon:ButtonText] forced-colors:data-[hover]:[--btn-icon:ButtonText]",
|
||||||
default: "h-10 px-4 py-2",
|
],
|
||||||
sm: "h-9 rounded-md px-3",
|
solid: [
|
||||||
lg: "h-11 rounded-md px-8",
|
// Optical border, implemented as the button background to avoid corner artifacts
|
||||||
icon: "h-10 w-10",
|
"border-transparent bg-[--btn-border]",
|
||||||
},
|
|
||||||
|
// Dark mode: border is rendered on `after` so background is set to button background
|
||||||
|
"dark:bg-[--btn-bg]",
|
||||||
|
|
||||||
|
// Button background, implemented as foreground layer to stack on top of pseudo-border layer
|
||||||
|
"before:absolute before:inset-0 before:-z-10 before:rounded-[calc(theme(borderRadius.lg)-1px)] before:bg-[--btn-bg]",
|
||||||
|
|
||||||
|
// Drop shadow, applied to the inset `before` layer so it blends with the border
|
||||||
|
"before:shadow",
|
||||||
|
|
||||||
|
// Background color is moved to control and shadow is removed in dark mode so hide `before` pseudo
|
||||||
|
"dark:before:hidden",
|
||||||
|
|
||||||
|
// Dark mode: Subtle white outline is applied using a border
|
||||||
|
"dark:border-white/5",
|
||||||
|
|
||||||
|
// Shim/overlay, inset to match button foreground and used for hover state + highlight shadow
|
||||||
|
"after:absolute after:inset-0 after:-z-10 after:rounded-[calc(theme(borderRadius.lg)-1px)]",
|
||||||
|
|
||||||
|
// Inner highlight shadow
|
||||||
|
"after:shadow-[shadow:inset_0_1px_theme(colors.white/15%)]",
|
||||||
|
|
||||||
|
// White overlay on hover
|
||||||
|
"after:data-[active]:bg-[--btn-hover-overlay] after:data-[hover]:bg-[--btn-hover-overlay]",
|
||||||
|
|
||||||
|
// Dark mode: `after` layer expands to cover entire button
|
||||||
|
"dark:after:-inset-px dark:after:rounded-lg",
|
||||||
|
|
||||||
|
// Disabled
|
||||||
|
"before:data-[disabled]:shadow-none after:data-[disabled]:shadow-none",
|
||||||
|
],
|
||||||
|
outline: [
|
||||||
|
// Base
|
||||||
|
"border-zinc-950/10 text-zinc-950 data-[active]:bg-zinc-950/[2.5%] data-[hover]:bg-zinc-950/[2.5%]",
|
||||||
|
|
||||||
|
// Dark mode
|
||||||
|
"dark:border-white/15 dark:text-white dark:[--btn-bg:transparent] dark:data-[active]:bg-white/5 dark:data-[hover]:bg-white/5",
|
||||||
|
|
||||||
|
// Icon
|
||||||
|
"[--btn-icon:theme(colors.zinc.500)] data-[active]:[--btn-icon:theme(colors.zinc.700)] data-[hover]:[--btn-icon:theme(colors.zinc.700)] dark:data-[active]:[--btn-icon:theme(colors.zinc.400)] dark:data-[hover]:[--btn-icon:theme(colors.zinc.400)]",
|
||||||
|
],
|
||||||
|
plain: [
|
||||||
|
// Base
|
||||||
|
"border-transparent text-zinc-950 data-[active]:bg-zinc-950/5 data-[hover]:bg-zinc-950/5",
|
||||||
|
|
||||||
|
// Dark mode
|
||||||
|
"dark:text-white dark:data-[active]:bg-white/10 dark:data-[hover]:bg-white/10",
|
||||||
|
|
||||||
|
// Icon
|
||||||
|
"[--btn-icon:theme(colors.zinc.500)] data-[active]:[--btn-icon:theme(colors.zinc.700)] data-[hover]:[--btn-icon:theme(colors.zinc.700)] dark:[--btn-icon:theme(colors.zinc.500)] dark:data-[active]:[--btn-icon:theme(colors.zinc.400)] dark:data-[hover]:[--btn-icon:theme(colors.zinc.400)]",
|
||||||
|
],
|
||||||
|
colors: {
|
||||||
|
"dark/zinc": [
|
||||||
|
"text-white [--btn-bg:theme(colors.zinc.900)] [--btn-border:theme(colors.zinc.950/90%)] [--btn-hover-overlay:theme(colors.white/10%)]",
|
||||||
|
"dark:text-white dark:[--btn-bg:theme(colors.zinc.600)] dark:[--btn-hover-overlay:theme(colors.white/5%)]",
|
||||||
|
"[--btn-icon:theme(colors.zinc.400)] data-[active]:[--btn-icon:theme(colors.zinc.300)] data-[hover]:[--btn-icon:theme(colors.zinc.300)]",
|
||||||
|
],
|
||||||
|
light: [
|
||||||
|
"text-zinc-950 [--btn-bg:white] [--btn-border:theme(colors.zinc.950/10%)] [--btn-hover-overlay:theme(colors.zinc.950/2.5%)] data-[active]:[--btn-border:theme(colors.zinc.950/15%)] data-[hover]:[--btn-border:theme(colors.zinc.950/15%)]",
|
||||||
|
"dark:text-white dark:[--btn-hover-overlay:theme(colors.white/5%)] dark:[--btn-bg:theme(colors.zinc.800)]",
|
||||||
|
"[--btn-icon:theme(colors.zinc.500)] data-[active]:[--btn-icon:theme(colors.zinc.700)] data-[hover]:[--btn-icon:theme(colors.zinc.700)] dark:[--btn-icon:theme(colors.zinc.500)] dark:data-[active]:[--btn-icon:theme(colors.zinc.400)] dark:data-[hover]:[--btn-icon:theme(colors.zinc.400)]",
|
||||||
|
],
|
||||||
|
"dark/white": [
|
||||||
|
"text-white [--btn-bg:theme(colors.zinc.900)] [--btn-border:theme(colors.zinc.950/90%)] [--btn-hover-overlay:theme(colors.white/10%)]",
|
||||||
|
"dark:text-zinc-950 dark:[--btn-bg:white] dark:[--btn-hover-overlay:theme(colors.zinc.950/5%)]",
|
||||||
|
"[--btn-icon:theme(colors.zinc.400)] data-[active]:[--btn-icon:theme(colors.zinc.300)] data-[hover]:[--btn-icon:theme(colors.zinc.300)] dark:[--btn-icon:theme(colors.zinc.500)] dark:data-[active]:[--btn-icon:theme(colors.zinc.400)] dark:data-[hover]:[--btn-icon:theme(colors.zinc.400)]",
|
||||||
|
],
|
||||||
|
dark: [
|
||||||
|
"text-white [--btn-bg:theme(colors.zinc.900)] [--btn-border:theme(colors.zinc.950/90%)] [--btn-hover-overlay:theme(colors.white/10%)]",
|
||||||
|
"dark:[--btn-hover-overlay:theme(colors.white/5%)] dark:[--btn-bg:theme(colors.zinc.800)]",
|
||||||
|
"[--btn-icon:theme(colors.zinc.400)] data-[active]:[--btn-icon:theme(colors.zinc.300)] data-[hover]:[--btn-icon:theme(colors.zinc.300)]",
|
||||||
|
],
|
||||||
|
white: [
|
||||||
|
"text-zinc-950 [--btn-bg:white] [--btn-border:theme(colors.zinc.950/10%)] [--btn-hover-overlay:theme(colors.zinc.950/2.5%)] data-[active]:[--btn-border:theme(colors.zinc.950/15%)] data-[hover]:[--btn-border:theme(colors.zinc.950/15%)]",
|
||||||
|
"dark:[--btn-hover-overlay:theme(colors.zinc.950/5%)]",
|
||||||
|
"[--btn-icon:theme(colors.zinc.400)] data-[active]:[--btn-icon:theme(colors.zinc.500)] data-[hover]:[--btn-icon:theme(colors.zinc.500)]",
|
||||||
|
],
|
||||||
|
zinc: [
|
||||||
|
"text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.zinc.600)] [--btn-border:theme(colors.zinc.700/90%)]",
|
||||||
|
"dark:[--btn-hover-overlay:theme(colors.white/5%)]",
|
||||||
|
"[--btn-icon:theme(colors.zinc.400)] data-[active]:[--btn-icon:theme(colors.zinc.300)] data-[hover]:[--btn-icon:theme(colors.zinc.300)]",
|
||||||
|
],
|
||||||
|
indigo: [
|
||||||
|
"text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.indigo.500)] [--btn-border:theme(colors.indigo.600/90%)]",
|
||||||
|
"[--btn-icon:theme(colors.indigo.300)] data-[active]:[--btn-icon:theme(colors.indigo.200)] data-[hover]:[--btn-icon:theme(colors.indigo.200)]",
|
||||||
|
],
|
||||||
|
cyan: [
|
||||||
|
"text-cyan-950 [--btn-bg:theme(colors.cyan.300)] [--btn-border:theme(colors.cyan.400/80%)] [--btn-hover-overlay:theme(colors.white/25%)]",
|
||||||
|
"[--btn-icon:theme(colors.cyan.500)]",
|
||||||
|
],
|
||||||
|
red: [
|
||||||
|
"text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.red.600)] [--btn-border:theme(colors.red.700/90%)]",
|
||||||
|
"[--btn-icon:theme(colors.red.300)] data-[active]:[--btn-icon:theme(colors.red.200)] data-[hover]:[--btn-icon:theme(colors.red.200)]",
|
||||||
|
],
|
||||||
|
orange: [
|
||||||
|
"text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.orange.500)] [--btn-border:theme(colors.orange.600/90%)]",
|
||||||
|
"[--btn-icon:theme(colors.orange.300)] data-[active]:[--btn-icon:theme(colors.orange.200)] data-[hover]:[--btn-icon:theme(colors.orange.200)]",
|
||||||
|
],
|
||||||
|
amber: [
|
||||||
|
"text-amber-950 [--btn-hover-overlay:theme(colors.white/25%)] [--btn-bg:theme(colors.amber.400)] [--btn-border:theme(colors.amber.500/80%)]",
|
||||||
|
"[--btn-icon:theme(colors.amber.600)]",
|
||||||
|
],
|
||||||
|
yellow: [
|
||||||
|
"text-yellow-950 [--btn-hover-overlay:theme(colors.white/25%)] [--btn-bg:theme(colors.yellow.300)] [--btn-border:theme(colors.yellow.400/80%)]",
|
||||||
|
"[--btn-icon:theme(colors.yellow.600)] data-[active]:[--btn-icon:theme(colors.yellow.700)] data-[hover]:[--btn-icon:theme(colors.yellow.700)]",
|
||||||
|
],
|
||||||
|
lime: [
|
||||||
|
"text-lime-950 [--btn-hover-overlay:theme(colors.white/25%)] [--btn-bg:theme(colors.lime.300)] [--btn-border:theme(colors.lime.400/80%)]",
|
||||||
|
"[--btn-icon:theme(colors.lime.600)] data-[active]:[--btn-icon:theme(colors.lime.700)] data-[hover]:[--btn-icon:theme(colors.lime.700)]",
|
||||||
|
],
|
||||||
|
green: [
|
||||||
|
"text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.green.600)] [--btn-border:theme(colors.green.700/90%)]",
|
||||||
|
"[--btn-icon:theme(colors.white/60%)] data-[active]:[--btn-icon:theme(colors.white/80%)] data-[hover]:[--btn-icon:theme(colors.white/80%)]",
|
||||||
|
],
|
||||||
|
emerald: [
|
||||||
|
"text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.emerald.600)] [--btn-border:theme(colors.emerald.700/90%)]",
|
||||||
|
"[--btn-icon:theme(colors.white/60%)] data-[active]:[--btn-icon:theme(colors.white/80%)] data-[hover]:[--btn-icon:theme(colors.white/80%)]",
|
||||||
|
],
|
||||||
|
teal: [
|
||||||
|
"text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.teal.600)] [--btn-border:theme(colors.teal.700/90%)]",
|
||||||
|
"[--btn-icon:theme(colors.white/60%)] data-[active]:[--btn-icon:theme(colors.white/80%)] data-[hover]:[--btn-icon:theme(colors.white/80%)]",
|
||||||
|
],
|
||||||
|
sky: [
|
||||||
|
"text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.sky.500)] [--btn-border:theme(colors.sky.600/80%)]",
|
||||||
|
"[--btn-icon:theme(colors.white/60%)] data-[active]:[--btn-icon:theme(colors.white/80%)] data-[hover]:[--btn-icon:theme(colors.white/80%)]",
|
||||||
|
],
|
||||||
|
blue: [
|
||||||
|
"text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.blue.600)] [--btn-border:theme(colors.blue.700/90%)]",
|
||||||
|
"[--btn-icon:theme(colors.blue.400)] data-[active]:[--btn-icon:theme(colors.blue.300)] data-[hover]:[--btn-icon:theme(colors.blue.300)]",
|
||||||
|
],
|
||||||
|
violet: [
|
||||||
|
"text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.violet.500)] [--btn-border:theme(colors.violet.600/90%)]",
|
||||||
|
"[--btn-icon:theme(colors.violet.300)] data-[active]:[--btn-icon:theme(colors.violet.200)] data-[hover]:[--btn-icon:theme(colors.violet.200)]",
|
||||||
|
],
|
||||||
|
purple: [
|
||||||
|
"text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.purple.500)] [--btn-border:theme(colors.purple.600/90%)]",
|
||||||
|
"[--btn-icon:theme(colors.purple.300)] data-[active]:[--btn-icon:theme(colors.purple.200)] data-[hover]:[--btn-icon:theme(colors.purple.200)]",
|
||||||
|
],
|
||||||
|
fuchsia: [
|
||||||
|
"text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.fuchsia.500)] [--btn-border:theme(colors.fuchsia.600/90%)]",
|
||||||
|
"[--btn-icon:theme(colors.fuchsia.300)] data-[active]:[--btn-icon:theme(colors.fuchsia.200)] data-[hover]:[--btn-icon:theme(colors.fuchsia.200)]",
|
||||||
|
],
|
||||||
|
pink: [
|
||||||
|
"text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.pink.500)] [--btn-border:theme(colors.pink.600/90%)]",
|
||||||
|
"[--btn-icon:theme(colors.pink.300)] data-[active]:[--btn-icon:theme(colors.pink.200)] data-[hover]:[--btn-icon:theme(colors.pink.200)]",
|
||||||
|
],
|
||||||
|
rose: [
|
||||||
|
"text-white [--btn-hover-overlay:theme(colors.white/10%)] [--btn-bg:theme(colors.rose.500)] [--btn-border:theme(colors.rose.600/90%)]",
|
||||||
|
"[--btn-icon:theme(colors.rose.300)] data-[active]:[--btn-icon:theme(colors.rose.200)] data-[hover]:[--btn-icon:theme(colors.rose.200)]",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const buttonVariants = cva(styles.base, {
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: [...styles.solid, ...styles.colors.zinc],
|
||||||
|
destructive: [...styles.solid, ...styles.colors.red],
|
||||||
|
outline: styles.outline,
|
||||||
|
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||||
|
ghost: styles.plain,
|
||||||
|
link: "border-none text-primary underline-offset-4 hover:underline",
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
size: {
|
||||||
variant: "default",
|
default: "h-10 px-4 py-2",
|
||||||
size: "default",
|
sm: "h-9 rounded-md px-3",
|
||||||
|
lg: "h-11 rounded-md px-8",
|
||||||
|
icon: "h-10 w-10",
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
defaultVariants: {
|
||||||
|
variant: "default",
|
||||||
|
size: "default",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export interface ButtonProps
|
export interface ButtonProps
|
||||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||||
|
|||||||
@@ -0,0 +1,262 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import useEmblaCarousel, {
|
||||||
|
type UseEmblaCarouselType,
|
||||||
|
} from "embla-carousel-react"
|
||||||
|
import { ArrowLeft, ArrowRight } from "lucide-react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
|
||||||
|
type CarouselApi = UseEmblaCarouselType[1]
|
||||||
|
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
|
||||||
|
type CarouselOptions = UseCarouselParameters[0]
|
||||||
|
type CarouselPlugin = UseCarouselParameters[1]
|
||||||
|
|
||||||
|
type CarouselProps = {
|
||||||
|
opts?: CarouselOptions
|
||||||
|
plugins?: CarouselPlugin
|
||||||
|
orientation?: "horizontal" | "vertical"
|
||||||
|
setApi?: (api: CarouselApi) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
type CarouselContextProps = {
|
||||||
|
carouselRef: ReturnType<typeof useEmblaCarousel>[0]
|
||||||
|
api: ReturnType<typeof useEmblaCarousel>[1]
|
||||||
|
scrollPrev: () => void
|
||||||
|
scrollNext: () => void
|
||||||
|
canScrollPrev: boolean
|
||||||
|
canScrollNext: boolean
|
||||||
|
} & CarouselProps
|
||||||
|
|
||||||
|
const CarouselContext = React.createContext<CarouselContextProps | null>(null)
|
||||||
|
|
||||||
|
function useCarousel() {
|
||||||
|
const context = React.useContext(CarouselContext)
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
throw new Error("useCarousel must be used within a <Carousel />")
|
||||||
|
}
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
const Carousel = React.forwardRef<
|
||||||
|
HTMLDivElement,
|
||||||
|
React.HTMLAttributes<HTMLDivElement> & CarouselProps
|
||||||
|
>(
|
||||||
|
(
|
||||||
|
{
|
||||||
|
orientation = "horizontal",
|
||||||
|
opts,
|
||||||
|
setApi,
|
||||||
|
plugins,
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
},
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
|
const [carouselRef, api] = useEmblaCarousel(
|
||||||
|
{
|
||||||
|
...opts,
|
||||||
|
axis: orientation === "horizontal" ? "x" : "y",
|
||||||
|
},
|
||||||
|
plugins
|
||||||
|
)
|
||||||
|
const [canScrollPrev, setCanScrollPrev] = React.useState(false)
|
||||||
|
const [canScrollNext, setCanScrollNext] = React.useState(false)
|
||||||
|
|
||||||
|
const onSelect = React.useCallback((api: CarouselApi) => {
|
||||||
|
if (!api) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setCanScrollPrev(api.canScrollPrev())
|
||||||
|
setCanScrollNext(api.canScrollNext())
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const scrollPrev = React.useCallback(() => {
|
||||||
|
api?.scrollPrev()
|
||||||
|
}, [api])
|
||||||
|
|
||||||
|
const scrollNext = React.useCallback(() => {
|
||||||
|
api?.scrollNext()
|
||||||
|
}, [api])
|
||||||
|
|
||||||
|
const handleKeyDown = React.useCallback(
|
||||||
|
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
||||||
|
if (event.key === "ArrowLeft") {
|
||||||
|
event.preventDefault()
|
||||||
|
scrollPrev()
|
||||||
|
} else if (event.key === "ArrowRight") {
|
||||||
|
event.preventDefault()
|
||||||
|
scrollNext()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[scrollPrev, scrollNext]
|
||||||
|
)
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!api || !setApi) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setApi(api)
|
||||||
|
}, [api, setApi])
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!api) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelect(api)
|
||||||
|
api.on("reInit", onSelect)
|
||||||
|
api.on("select", onSelect)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
api?.off("select", onSelect)
|
||||||
|
}
|
||||||
|
}, [api, onSelect])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CarouselContext.Provider
|
||||||
|
value={{
|
||||||
|
carouselRef,
|
||||||
|
api: api,
|
||||||
|
opts,
|
||||||
|
orientation:
|
||||||
|
orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
|
||||||
|
scrollPrev,
|
||||||
|
scrollNext,
|
||||||
|
canScrollPrev,
|
||||||
|
canScrollNext,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
onKeyDownCapture={handleKeyDown}
|
||||||
|
className={cn("relative", className)}
|
||||||
|
role="region"
|
||||||
|
aria-roledescription="carousel"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</CarouselContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Carousel.displayName = "Carousel"
|
||||||
|
|
||||||
|
const CarouselContent = React.forwardRef<
|
||||||
|
HTMLDivElement,
|
||||||
|
React.HTMLAttributes<HTMLDivElement>
|
||||||
|
>(({ className, ...props }, ref) => {
|
||||||
|
const { carouselRef, orientation } = useCarousel()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={carouselRef} className="overflow-hidden">
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex",
|
||||||
|
orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
CarouselContent.displayName = "CarouselContent"
|
||||||
|
|
||||||
|
const CarouselItem = React.forwardRef<
|
||||||
|
HTMLDivElement,
|
||||||
|
React.HTMLAttributes<HTMLDivElement>
|
||||||
|
>(({ className, ...props }, ref) => {
|
||||||
|
const { orientation } = useCarousel()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
role="group"
|
||||||
|
aria-roledescription="slide"
|
||||||
|
className={cn(
|
||||||
|
"min-w-0 shrink-0 grow-0 basis-full",
|
||||||
|
orientation === "horizontal" ? "pl-4" : "pt-4",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
CarouselItem.displayName = "CarouselItem"
|
||||||
|
|
||||||
|
const CarouselPrevious = React.forwardRef<
|
||||||
|
HTMLButtonElement,
|
||||||
|
React.ComponentProps<typeof Button>
|
||||||
|
>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
|
||||||
|
const { orientation, scrollPrev, canScrollPrev } = useCarousel()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
ref={ref}
|
||||||
|
variant={variant}
|
||||||
|
size={size}
|
||||||
|
className={cn(
|
||||||
|
"absolute h-8 w-8 rounded-full",
|
||||||
|
orientation === "horizontal"
|
||||||
|
? "-left-12 top-1/2 -translate-y-1/2"
|
||||||
|
: "-top-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
disabled={!canScrollPrev}
|
||||||
|
onClick={scrollPrev}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ArrowLeft className="h-4 w-4" />
|
||||||
|
<span className="sr-only">Previous slide</span>
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
CarouselPrevious.displayName = "CarouselPrevious"
|
||||||
|
|
||||||
|
const CarouselNext = React.forwardRef<
|
||||||
|
HTMLButtonElement,
|
||||||
|
React.ComponentProps<typeof Button>
|
||||||
|
>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
|
||||||
|
const { orientation, scrollNext, canScrollNext } = useCarousel()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
ref={ref}
|
||||||
|
variant={variant}
|
||||||
|
size={size}
|
||||||
|
className={cn(
|
||||||
|
"absolute h-8 w-8 rounded-full",
|
||||||
|
orientation === "horizontal"
|
||||||
|
? "-right-12 top-1/2 -translate-y-1/2"
|
||||||
|
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
disabled={!canScrollNext}
|
||||||
|
onClick={scrollNext}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ArrowRight className="h-4 w-4" />
|
||||||
|
<span className="sr-only">Next slide</span>
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
CarouselNext.displayName = "CarouselNext"
|
||||||
|
|
||||||
|
export {
|
||||||
|
type CarouselApi,
|
||||||
|
Carousel,
|
||||||
|
CarouselContent,
|
||||||
|
CarouselItem,
|
||||||
|
CarouselPrevious,
|
||||||
|
CarouselNext,
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { callServerPromise } from "@/components/callServerPromise";
|
||||||
|
import { useEffect, useState, useTransition } from "react";
|
||||||
|
|
||||||
|
export function useServerActionData<I, O>(
|
||||||
|
action: (data: I) => Promise<O>,
|
||||||
|
input: I
|
||||||
|
) {
|
||||||
|
const [data, setData] = useState<O | null>(null);
|
||||||
|
const [pending, startTransition] = useTransition();
|
||||||
|
const [started, setStarted] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
startTransition(() => {
|
||||||
|
setStarted(true);
|
||||||
|
callServerPromise(action(input)).then(setData);
|
||||||
|
});
|
||||||
|
}, [action, input]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
started,
|
||||||
|
data,
|
||||||
|
pending,
|
||||||
|
};
|
||||||
|
}
|
||||||
+12
-4
@@ -1,11 +1,19 @@
|
|||||||
import * as schema from "./schema";
|
import { Pool, neonConfig } from "@neondatabase/serverless";
|
||||||
import { neonConfig, Pool } from "@neondatabase/serverless";
|
|
||||||
import { drizzle as neonDrizzle } from "drizzle-orm/neon-serverless";
|
import { drizzle as neonDrizzle } from "drizzle-orm/neon-serverless";
|
||||||
|
import * as schema from "./schema";
|
||||||
|
|
||||||
|
const isDevContainer = process.env.REMOTE_CONTAINERS !== undefined;
|
||||||
|
|
||||||
// if we're running locally
|
// if we're running locally
|
||||||
if (process.env.VERCEL_ENV !== "production") {
|
if (process.env.VERCEL_ENV !== "production") {
|
||||||
// Set the WebSocket proxy to work with the local instance
|
// Set the WebSocket proxy to work with the local instance
|
||||||
neonConfig.wsProxy = (host) => `${host}:5481/v1`;
|
if (isDevContainer) {
|
||||||
|
// Running inside a VS Code devcontainer
|
||||||
|
neonConfig.wsProxy = (host) => "host.docker.internal:5481/v1";
|
||||||
|
} else {
|
||||||
|
// Not running inside a VS Code devcontainer
|
||||||
|
neonConfig.wsProxy = (host) => `${host}:5481/v1`;
|
||||||
|
}
|
||||||
// Disable all authentication and encryption
|
// Disable all authentication and encryption
|
||||||
neonConfig.useSecureWebSocket = false;
|
neonConfig.useSecureWebSocket = false;
|
||||||
neonConfig.pipelineTLS = false;
|
neonConfig.pipelineTLS = false;
|
||||||
@@ -18,5 +26,5 @@ export const db = neonDrizzle(
|
|||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
schema,
|
schema,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
+69
-13
@@ -1,15 +1,15 @@
|
|||||||
import { relations, type InferSelectModel } from "drizzle-orm";
|
import { type InferSelectModel, relations } from "drizzle-orm";
|
||||||
import {
|
import {
|
||||||
text,
|
boolean,
|
||||||
pgSchema,
|
|
||||||
uuid,
|
|
||||||
integer,
|
integer,
|
||||||
timestamp,
|
|
||||||
jsonb,
|
jsonb,
|
||||||
pgEnum,
|
pgEnum,
|
||||||
boolean,
|
pgSchema,
|
||||||
|
text,
|
||||||
|
timestamp,
|
||||||
|
uuid,
|
||||||
} from "drizzle-orm/pg-core";
|
} from "drizzle-orm/pg-core";
|
||||||
import { createInsertSchema } from "drizzle-zod";
|
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const dbSchema = pgSchema("comfyui_deploy");
|
export const dbSchema = pgSchema("comfyui_deploy");
|
||||||
@@ -35,7 +35,13 @@ export const workflowTable = dbSchema.table("workflows", {
|
|||||||
updated_at: timestamp("updated_at").defaultNow().notNull(),
|
updated_at: timestamp("updated_at").defaultNow().notNull(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const workflowRelations = relations(workflowTable, ({ many }) => ({
|
export const workflowSchema = createSelectSchema(workflowTable);
|
||||||
|
|
||||||
|
export const workflowRelations = relations(workflowTable, ({ many, one }) => ({
|
||||||
|
user: one(usersTable, {
|
||||||
|
fields: [workflowTable.user_id],
|
||||||
|
references: [usersTable.id],
|
||||||
|
}),
|
||||||
versions: many(workflowVersionTable),
|
versions: many(workflowVersionTable),
|
||||||
deployments: many(deploymentsTable),
|
deployments: many(deploymentsTable),
|
||||||
}));
|
}));
|
||||||
@@ -75,6 +81,7 @@ export const workflowVersionTable = dbSchema.table("workflow_versions", {
|
|||||||
created_at: timestamp("created_at").defaultNow().notNull(),
|
created_at: timestamp("created_at").defaultNow().notNull(),
|
||||||
updated_at: timestamp("updated_at").defaultNow().notNull(),
|
updated_at: timestamp("updated_at").defaultNow().notNull(),
|
||||||
});
|
});
|
||||||
|
export const workflowVersionSchema = createSelectSchema(workflowVersionTable);
|
||||||
|
|
||||||
export const workflowVersionRelations = relations(
|
export const workflowVersionRelations = relations(
|
||||||
workflowVersionTable,
|
workflowVersionTable,
|
||||||
@@ -83,7 +90,7 @@ export const workflowVersionRelations = relations(
|
|||||||
fields: [workflowVersionTable.workflow_id],
|
fields: [workflowVersionTable.workflow_id],
|
||||||
references: [workflowTable.id],
|
references: [workflowTable.id],
|
||||||
}),
|
}),
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const workflowRunStatus = pgEnum("workflow_run_status", [
|
export const workflowRunStatus = pgEnum("workflow_run_status", [
|
||||||
@@ -103,8 +110,12 @@ export const deploymentEnvironment = pgEnum("deployment_environment", [
|
|||||||
export const workflowRunOrigin = pgEnum("workflow_run_origin", [
|
export const workflowRunOrigin = pgEnum("workflow_run_origin", [
|
||||||
"manual",
|
"manual",
|
||||||
"api",
|
"api",
|
||||||
|
"public-share",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
export const WorkflowRunOriginSchema = z.enum(workflowRunOrigin.enumValues);
|
||||||
|
export type WorkflowRunOriginType = z.infer<typeof WorkflowRunOriginSchema>;
|
||||||
|
|
||||||
export const machineGPUOptions = pgEnum("machine_gpu", ["T4", "A10G", "A100"]);
|
export const machineGPUOptions = pgEnum("machine_gpu", ["T4", "A10G", "A100"]);
|
||||||
|
|
||||||
export const machinesType = pgEnum("machine_type", [
|
export const machinesType = pgEnum("machine_type", [
|
||||||
@@ -128,7 +139,7 @@ export const workflowRunsTable = dbSchema.table("workflow_runs", {
|
|||||||
() => workflowVersionTable.id,
|
() => workflowVersionTable.id,
|
||||||
{
|
{
|
||||||
onDelete: "set null",
|
onDelete: "set null",
|
||||||
}
|
},
|
||||||
),
|
),
|
||||||
workflow_inputs:
|
workflow_inputs:
|
||||||
jsonb("workflow_inputs").$type<Record<string, string | number>>(),
|
jsonb("workflow_inputs").$type<Record<string, string | number>>(),
|
||||||
@@ -145,6 +156,7 @@ export const workflowRunsTable = dbSchema.table("workflow_runs", {
|
|||||||
status: workflowRunStatus("status").notNull().default("not-started"),
|
status: workflowRunStatus("status").notNull().default("not-started"),
|
||||||
ended_at: timestamp("ended_at"),
|
ended_at: timestamp("ended_at"),
|
||||||
created_at: timestamp("created_at").defaultNow().notNull(),
|
created_at: timestamp("created_at").defaultNow().notNull(),
|
||||||
|
started_at: timestamp("started_at"),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const workflowRunRelations = relations(
|
export const workflowRunRelations = relations(
|
||||||
@@ -163,7 +175,7 @@ export const workflowRunRelations = relations(
|
|||||||
fields: [workflowRunsTable.workflow_id],
|
fields: [workflowRunsTable.workflow_id],
|
||||||
references: [workflowTable.id],
|
references: [workflowTable.id],
|
||||||
}),
|
}),
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// We still want to keep the workflow run record.
|
// We still want to keep the workflow run record.
|
||||||
@@ -187,7 +199,7 @@ export const workflowOutputRelations = relations(
|
|||||||
fields: [workflowRunOutputs.run_id],
|
fields: [workflowRunOutputs.run_id],
|
||||||
references: [workflowRunsTable.id],
|
references: [workflowRunsTable.id],
|
||||||
}),
|
}),
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// when user delete, also delete all the workflow versions
|
// when user delete, also delete all the workflow versions
|
||||||
@@ -220,7 +232,7 @@ export const snapshotType = z.object({
|
|||||||
z.object({
|
z.object({
|
||||||
hash: z.string(),
|
hash: z.string(),
|
||||||
disabled: z.boolean(),
|
disabled: z.boolean(),
|
||||||
})
|
}),
|
||||||
),
|
),
|
||||||
file_custom_nodes: z.array(z.any()),
|
file_custom_nodes: z.array(z.any()),
|
||||||
});
|
});
|
||||||
@@ -231,6 +243,22 @@ export const insertMachineSchema = createInsertSchema(machinesTable, {
|
|||||||
type: (schema) => schema.type.default("classic"),
|
type: (schema) => schema.type.default("classic"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const showcaseMedia = z.array(
|
||||||
|
z.object({
|
||||||
|
url: z.string(),
|
||||||
|
isCover: z.boolean().default(false),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const showcaseMediaNullable = z
|
||||||
|
.array(
|
||||||
|
z.object({
|
||||||
|
url: z.string(),
|
||||||
|
isCover: z.boolean().default(false),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.nullable();
|
||||||
|
|
||||||
export const deploymentsTable = dbSchema.table("deployments", {
|
export const deploymentsTable = dbSchema.table("deployments", {
|
||||||
id: uuid("id").primaryKey().defaultRandom().notNull(),
|
id: uuid("id").primaryKey().defaultRandom().notNull(),
|
||||||
user_id: text("user_id")
|
user_id: text("user_id")
|
||||||
@@ -238,6 +266,7 @@ export const deploymentsTable = dbSchema.table("deployments", {
|
|||||||
onDelete: "cascade",
|
onDelete: "cascade",
|
||||||
})
|
})
|
||||||
.notNull(),
|
.notNull(),
|
||||||
|
org_id: text("org_id"),
|
||||||
workflow_version_id: uuid("workflow_version_id")
|
workflow_version_id: uuid("workflow_version_id")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => workflowVersionTable.id),
|
.references(() => workflowVersionTable.id),
|
||||||
@@ -249,11 +278,28 @@ export const deploymentsTable = dbSchema.table("deployments", {
|
|||||||
machine_id: uuid("machine_id")
|
machine_id: uuid("machine_id")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => machinesTable.id),
|
.references(() => machinesTable.id),
|
||||||
|
share_slug: text("share_slug").unique(),
|
||||||
|
description: text("description"),
|
||||||
|
showcase_media:
|
||||||
|
jsonb("showcase_media").$type<z.infer<typeof showcaseMedia>>(),
|
||||||
environment: deploymentEnvironment("environment").notNull(),
|
environment: deploymentEnvironment("environment").notNull(),
|
||||||
created_at: timestamp("created_at").defaultNow().notNull(),
|
created_at: timestamp("created_at").defaultNow().notNull(),
|
||||||
updated_at: timestamp("updated_at").defaultNow().notNull(),
|
updated_at: timestamp("updated_at").defaultNow().notNull(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const publicShareDeployment = z.object({
|
||||||
|
description: z.string().nullable(),
|
||||||
|
showcase_media: showcaseMedia,
|
||||||
|
});
|
||||||
|
|
||||||
|
// createInsertSchema(deploymentsTable, {
|
||||||
|
// description: (schema) => schema.description.default(""),
|
||||||
|
// showcase_media: () => showcaseMedia.default([]),
|
||||||
|
// }).pick({
|
||||||
|
// description: true,
|
||||||
|
// showcase_media: true,
|
||||||
|
// });
|
||||||
|
|
||||||
export const deploymentsRelations = relations(deploymentsTable, ({ one }) => ({
|
export const deploymentsRelations = relations(deploymentsTable, ({ one }) => ({
|
||||||
machine: one(machinesTable, {
|
machine: one(machinesTable, {
|
||||||
fields: [deploymentsTable.machine_id],
|
fields: [deploymentsTable.machine_id],
|
||||||
@@ -288,6 +334,16 @@ export const apiKeyTable = dbSchema.table("api_keys", {
|
|||||||
updated_at: timestamp("updated_at").defaultNow().notNull(),
|
updated_at: timestamp("updated_at").defaultNow().notNull(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const authRequestsTable = dbSchema.table("auth_requests", {
|
||||||
|
request_id: text("request_id").primaryKey().notNull(),
|
||||||
|
user_id: text("user_id"),
|
||||||
|
org_id: text("org_id"),
|
||||||
|
api_hash: text("api_hash"),
|
||||||
|
created_at: timestamp("created_at").defaultNow().notNull(),
|
||||||
|
expired_date: timestamp("expired_date"),
|
||||||
|
updated_at: timestamp("updated_at").defaultNow().notNull(),
|
||||||
|
});
|
||||||
|
|
||||||
export type UserType = InferSelectModel<typeof usersTable>;
|
export type UserType = InferSelectModel<typeof usersTable>;
|
||||||
export type WorkflowType = InferSelectModel<typeof workflowTable>;
|
export type WorkflowType = InferSelectModel<typeof workflowTable>;
|
||||||
export type MachineType = InferSelectModel<typeof machinesTable>;
|
export type MachineType = InferSelectModel<typeof machinesTable>;
|
||||||
|
|||||||
@@ -1,12 +1,26 @@
|
|||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
import duration from "dayjs/plugin/duration";
|
||||||
import relativeTime from "dayjs/plugin/relativeTime";
|
import relativeTime from "dayjs/plugin/relativeTime";
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
|
dayjs.extend(duration);
|
||||||
export function getRelativeTime(time: string | Date | null | undefined) {
|
export function getRelativeTime(time: string | Date | null | undefined) {
|
||||||
if (typeof time === "string" || time instanceof Date) {
|
if (typeof time === "string" || time instanceof Date) {
|
||||||
return dayjs().to(time);
|
return dayjs().to(time);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatDuration(seconds: number) {
|
||||||
|
const minutes = Math.floor(seconds / 60);
|
||||||
|
const remainingSeconds = seconds % 60;
|
||||||
|
if (minutes > 0) {
|
||||||
|
return `${minutes}.${remainingSeconds} mins`;
|
||||||
|
} else {
|
||||||
|
return `${remainingSeconds.toFixed(1)} secs`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDuration(durationInSecs: number) {
|
||||||
|
return `${formatDuration(durationInSecs)}`;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
export function remToPx(remValue: number) {
|
export function remToPx(remValue: number) {
|
||||||
let rootFontSize =
|
const rootFontSize =
|
||||||
typeof window === 'undefined'
|
typeof window === "undefined"
|
||||||
? 16
|
? 16
|
||||||
: parseFloat(window.getComputedStyle(document.documentElement).fontSize)
|
: parseFloat(
|
||||||
|
window.getComputedStyle(document.documentElement).fontSize,
|
||||||
|
);
|
||||||
|
|
||||||
return remValue * rootFontSize
|
return remValue * rootFontSize
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -27,13 +27,13 @@ function rehypeShiki() {
|
|||||||
|
|
||||||
visit(tree, "element", (node) => {
|
visit(tree, "element", (node) => {
|
||||||
if (node.tagName === "pre" && node.children[0]?.tagName === "code") {
|
if (node.tagName === "pre" && node.children[0]?.tagName === "code") {
|
||||||
let codeNode = node.children[0];
|
const codeNode = node.children[0];
|
||||||
let textNode = codeNode.children[0];
|
const textNode = codeNode.children[0];
|
||||||
|
|
||||||
node.properties.code = textNode.value;
|
node.properties.code = textNode.value;
|
||||||
|
|
||||||
if (node.properties.language) {
|
if (node.properties.language) {
|
||||||
let tokens = highlighter.codeToThemedTokens(
|
const tokens = highlighter.codeToThemedTokens(
|
||||||
textNode.value,
|
textNode.value,
|
||||||
node.properties.language
|
node.properties.language
|
||||||
);
|
);
|
||||||
@@ -53,7 +53,7 @@ function rehypeShiki() {
|
|||||||
|
|
||||||
function rehypeSlugify() {
|
function rehypeSlugify() {
|
||||||
return (tree) => {
|
return (tree) => {
|
||||||
let slugify = slugifyWithCounter();
|
const slugify = slugifyWithCounter();
|
||||||
visit(tree, "element", (node) => {
|
visit(tree, "element", (node) => {
|
||||||
if (node.tagName === "h2" && !node.properties.id) {
|
if (node.tagName === "h2" && !node.properties.id) {
|
||||||
node.properties.id = slugify(toString(node));
|
node.properties.id = slugify(toString(node));
|
||||||
@@ -64,10 +64,10 @@ function rehypeSlugify() {
|
|||||||
|
|
||||||
function rehypeAddMDXExports(getExports) {
|
function rehypeAddMDXExports(getExports) {
|
||||||
return (tree) => {
|
return (tree) => {
|
||||||
let exports = Object.entries(getExports(tree));
|
const exports = Object.entries(getExports(tree));
|
||||||
|
|
||||||
for (let [name, value] of exports) {
|
for (const [name, value] of exports) {
|
||||||
for (let node of tree.children) {
|
for (const node of tree.children) {
|
||||||
if (
|
if (
|
||||||
node.type === "mdxjsEsm" &&
|
node.type === "mdxjsEsm" &&
|
||||||
new RegExp(`export\\s+const\\s+${name}\\s*=`).test(node.value)
|
new RegExp(`export\\s+const\\s+${name}\\s*=`).test(node.value)
|
||||||
@@ -76,7 +76,7 @@ function rehypeAddMDXExports(getExports) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let exportStr = `export const ${name} = ${value}`;
|
const exportStr = `export const ${name} = ${value}`;
|
||||||
|
|
||||||
tree.children.push({
|
tree.children.push({
|
||||||
type: "mdxjsEsm",
|
type: "mdxjsEsm",
|
||||||
@@ -93,9 +93,9 @@ function rehypeAddMDXExports(getExports) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getSections(node) {
|
function getSections(node) {
|
||||||
let sections = [];
|
const sections = [];
|
||||||
|
|
||||||
for (let child of node.children ?? []) {
|
for (const child of node.children ?? []) {
|
||||||
if (child.type === "element" && child.tagName === "h2") {
|
if (child.type === "element" && child.tagName === "h2") {
|
||||||
sections.push(`{
|
sections.push(`{
|
||||||
title: ${JSON.stringify(toString(child))},
|
title: ${JSON.stringify(toString(child))},
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ function extractSections() {
|
|||||||
|
|
||||||
visit(tree, (node) => {
|
visit(tree, (node) => {
|
||||||
if (node.type === "heading" || node.type === "paragraph") {
|
if (node.type === "heading" || node.type === "paragraph") {
|
||||||
let content = toString(excludeObjectExpressions(node));
|
const content = toString(excludeObjectExpressions(node));
|
||||||
if (node.type === "heading" && node.depth <= 2) {
|
if (node.type === "heading" && node.depth <= 2) {
|
||||||
let hash = node.depth === 1 ? null : slugify(content);
|
const hash = node.depth === 1 ? null : slugify(content);
|
||||||
sections.push([content, hash, []]);
|
sections.push([content, hash, []]);
|
||||||
} else {
|
} else {
|
||||||
sections.at(-1)?.[2].push(content);
|
sections.at(-1)?.[2].push(content);
|
||||||
@@ -45,7 +45,7 @@ function extractSections() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function (nextConfig = {}) {
|
export default function (nextConfig = {}) {
|
||||||
let cache = new Map();
|
const cache = new Map();
|
||||||
|
|
||||||
return Object.assign({}, nextConfig, {
|
return Object.assign({}, nextConfig, {
|
||||||
webpack(config, options) {
|
webpack(config, options) {
|
||||||
@@ -53,20 +53,20 @@ export default function (nextConfig = {}) {
|
|||||||
test: __filename,
|
test: __filename,
|
||||||
use: [
|
use: [
|
||||||
createLoader(function () {
|
createLoader(function () {
|
||||||
let appDir = path.resolve("./src/app/(docs)/docs");
|
const appDir = path.resolve("./src/app/(docs)/docs");
|
||||||
this.addContextDependency(appDir);
|
this.addContextDependency(appDir);
|
||||||
|
|
||||||
let files = glob.sync("**/*.mdx", { cwd: appDir });
|
const files = glob.sync("**/*.mdx", { cwd: appDir });
|
||||||
let data = files.map((file) => {
|
const data = files.map((file) => {
|
||||||
let url = `/${file.replace(/(^|\/)page\.mdx$/, "")}`;
|
let url = `/${file.replace(/(^|\/)page\.mdx$/, "")}`;
|
||||||
let mdx = fs.readFileSync(path.join(appDir, file), "utf8");
|
const mdx = fs.readFileSync(path.join(appDir, file), "utf8");
|
||||||
|
|
||||||
let sections = [];
|
let sections = [];
|
||||||
|
|
||||||
if (cache.get(file)?.[0] === mdx) {
|
if (cache.get(file)?.[0] === mdx) {
|
||||||
sections = cache.get(file)[1];
|
sections = cache.get(file)[1];
|
||||||
} else {
|
} else {
|
||||||
let vfile = { value: mdx, sections };
|
const vfile = { value: mdx, sections };
|
||||||
processor.runSync(processor.parse(vfile), vfile);
|
processor.runSync(processor.parse(vfile), vfile);
|
||||||
cache.set(file, [mdx, sections]);
|
cache.set(file, [mdx, sections]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import type { ResponseConfig } from "@asteasolutions/zod-to-openapi";
|
import type { ResponseConfig } from "@asteasolutions/zod-to-openapi";
|
||||||
|
|
||||||
|
|
||||||
import { z } from "@hono/zod-openapi";
|
import { z } from "@hono/zod-openapi";
|
||||||
|
|
||||||
export const authError = {
|
export const authError = {
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { customAlphabet } from "nanoid";
|
||||||
|
|
||||||
|
export const nanoid = customAlphabet(
|
||||||
|
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",
|
||||||
|
);
|
||||||
|
const prefixes = {
|
||||||
|
img: "img",
|
||||||
|
vid: "vid",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export function newId(prefix: keyof typeof prefixes): string {
|
||||||
|
return [prefixes[prefix], nanoid(16)].join("_");
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user