From 6b431426ff3dcdd954c5e64dae6a96884d894438 Mon Sep 17 00:00:00 2001 From: BennyKok Date: Sat, 9 Dec 2023 00:10:59 +0800 Subject: [PATCH] feat: add comftui plugin, initial db --- .eslintrc.json | 3 - .gitignore | 37 +- .vscode/extensions.json | 14 + .vscode/settings.json | 17 + __init__.py | 52 +++ bun.lockb | Bin 134273 -> 0 bytes package.json | 27 -- routes.py | 22 ++ src/app/globals.css | 27 -- src/app/layout.tsx | 22 -- src/app/page.tsx | 113 ------ tailwind.config.ts | 20 - web-plugin/api.js | 4 + web-plugin/app.js | 4 + web-plugin/index.js | 214 +++++++++++ web-plugin/widgets.js | 18 + web/.eslintignore | 6 + web/.eslintrc.js | 94 +++++ web/.gitignore | 36 ++ README.md => web/README.md | 0 web/bun.lockb | Bin 0 -> 278816 bytes web/components.json | 16 + web/docker-compose.yml | 22 ++ web/drizzle.config.ts | 15 + web/drizzle/0000_quiet_ulik.sql | 75 ++++ web/drizzle/0001_silly_arachne.sql | 6 + web/drizzle/0002_clean_khan.sql | 1 + web/drizzle/meta/0000_snapshot.json | 320 ++++++++++++++++ web/drizzle/meta/0001_snapshot.json | 334 ++++++++++++++++ web/drizzle/meta/0002_snapshot.json | 334 ++++++++++++++++ web/drizzle/meta/_journal.json | 27 ++ web/migrate.mts | 41 ++ next.config.js => web/next.config.js | 0 web/package.json | 66 ++++ postcss.config.js => web/postcss.config.js | 2 +- web/prettier-preset.js | 39 ++ {public => web/public}/next.svg | 0 {public => web/public}/vercel.svg | 0 web/src/app/[workflow_id]/page.tsx | 64 ++++ web/src/app/api/create-run/route.ts | 56 +++ web/src/app/api/update-run/route.ts | 55 +++ web/src/app/api/upload/route.ts | 125 ++++++ {src => web/src}/app/favicon.ico | Bin web/src/app/globals.css | 76 ++++ web/src/app/layout.tsx | 36 ++ web/src/app/machines/page.tsx | 67 ++++ web/src/app/page.tsx | 77 ++++ web/src/components/MachineList.tsx | 425 +++++++++++++++++++++ web/src/components/NavbarRight.tsx | 29 ++ web/src/components/VersionSelect.tsx | 63 +++ web/src/components/WorkflowList.tsx | 309 +++++++++++++++ web/src/components/ui/button.tsx | 55 +++ web/src/components/ui/card.tsx | 79 ++++ web/src/components/ui/checkbox.tsx | 30 ++ web/src/components/ui/dialog.tsx | 122 ++++++ web/src/components/ui/dropdown-menu.tsx | 200 ++++++++++ web/src/components/ui/form.tsx | 176 +++++++++ web/src/components/ui/input.tsx | 25 ++ web/src/components/ui/label.tsx | 26 ++ web/src/components/ui/select.tsx | 160 ++++++++ web/src/components/ui/table.tsx | 117 ++++++ web/src/components/ui/tabs.tsx | 55 +++ web/src/db/db.ts | 22 ++ web/src/db/schema.ts | 142 +++++++ web/src/lib/getRelativeTime.tsx | 12 + web/src/lib/parseDataSafe.ts | 38 ++ web/src/lib/utils.ts | 6 + web/src/middleware.ts | 38 ++ web/src/server/curdMachine.ts | 46 +++ web/src/server/deleteWorkflow.ts | 13 + web/tailwind.config.ts | 78 ++++ tsconfig.json => web/tsconfig.json | 2 +- 72 files changed, 4602 insertions(+), 250 deletions(-) delete mode 100644 .eslintrc.json create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 __init__.py delete mode 100755 bun.lockb delete mode 100644 package.json create mode 100644 routes.py delete mode 100644 src/app/globals.css delete mode 100644 src/app/layout.tsx delete mode 100644 src/app/page.tsx delete mode 100644 tailwind.config.ts create mode 100644 web-plugin/api.js create mode 100644 web-plugin/app.js create mode 100644 web-plugin/index.js create mode 100644 web-plugin/widgets.js create mode 100644 web/.eslintignore create mode 100644 web/.eslintrc.js create mode 100644 web/.gitignore rename README.md => web/README.md (100%) create mode 100755 web/bun.lockb create mode 100644 web/components.json create mode 100644 web/docker-compose.yml create mode 100644 web/drizzle.config.ts create mode 100644 web/drizzle/0000_quiet_ulik.sql create mode 100644 web/drizzle/0001_silly_arachne.sql create mode 100644 web/drizzle/0002_clean_khan.sql create mode 100644 web/drizzle/meta/0000_snapshot.json create mode 100644 web/drizzle/meta/0001_snapshot.json create mode 100644 web/drizzle/meta/0002_snapshot.json create mode 100644 web/drizzle/meta/_journal.json create mode 100644 web/migrate.mts rename next.config.js => web/next.config.js (100%) create mode 100644 web/package.json rename postcss.config.js => web/postcss.config.js (96%) create mode 100644 web/prettier-preset.js rename {public => web/public}/next.svg (100%) rename {public => web/public}/vercel.svg (100%) create mode 100644 web/src/app/[workflow_id]/page.tsx create mode 100644 web/src/app/api/create-run/route.ts create mode 100644 web/src/app/api/update-run/route.ts create mode 100644 web/src/app/api/upload/route.ts rename {src => web/src}/app/favicon.ico (100%) create mode 100644 web/src/app/globals.css create mode 100644 web/src/app/layout.tsx create mode 100644 web/src/app/machines/page.tsx create mode 100644 web/src/app/page.tsx create mode 100644 web/src/components/MachineList.tsx create mode 100644 web/src/components/NavbarRight.tsx create mode 100644 web/src/components/VersionSelect.tsx create mode 100644 web/src/components/WorkflowList.tsx create mode 100644 web/src/components/ui/button.tsx create mode 100644 web/src/components/ui/card.tsx create mode 100644 web/src/components/ui/checkbox.tsx create mode 100644 web/src/components/ui/dialog.tsx create mode 100644 web/src/components/ui/dropdown-menu.tsx create mode 100644 web/src/components/ui/form.tsx create mode 100644 web/src/components/ui/input.tsx create mode 100644 web/src/components/ui/label.tsx create mode 100644 web/src/components/ui/select.tsx create mode 100644 web/src/components/ui/table.tsx create mode 100644 web/src/components/ui/tabs.tsx create mode 100644 web/src/db/db.ts create mode 100644 web/src/db/schema.ts create mode 100644 web/src/lib/getRelativeTime.tsx create mode 100644 web/src/lib/parseDataSafe.ts create mode 100644 web/src/lib/utils.ts create mode 100644 web/src/middleware.ts create mode 100644 web/src/server/curdMachine.ts create mode 100644 web/src/server/deleteWorkflow.ts create mode 100644 web/tailwind.config.ts rename tsconfig.json => web/tsconfig.json (96%) diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index bffb357..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "next/core-web-vitals" -} diff --git a/.gitignore b/.gitignore index fd3dbb5..ed8ebf5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,36 +1 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js -.yarn/install-state.gz - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env*.local - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts +__pycache__ \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..74cae7d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,14 @@ +{ + "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 + "ban.spellright", // Spell check for docs + "stripe.vscode-stripe", // stripe VSCode extension + "Prisma.prisma", // syntax|format|completion for prisma + "rebornix.project-snippets", // Share useful snippets between collaborators + "inlang.vs-code-extension" // improved i18n DX + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..fb52ab5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,17 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib", + "editor.formatOnSave": false, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true + }, + "typescript.preferences.importModuleSpecifier": "non-relative", + "spellright.language": ["en"], + "spellright.documentTypes": ["markdown", "typescript", "typescriptreact"], + "tailwindCSS.experimental.classRegex": [ + [ + "cva\\(([^)]*)\\)", + "[\"'`]([^\"'`]*).*?[\"'`]" + ] + ], + "eslint.workingDirectories": ["web"] +} diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..a4d13f9 --- /dev/null +++ b/__init__.py @@ -0,0 +1,52 @@ +""" +@author: BennyKok +@title: comfy-deploy +@nickname: Comfy Deploy +@description: +""" +import os +import sys + +sys.path.append(os.path.join(os.path.dirname(__file__))) + +import routes +import inspect +import sys +import importlib +import subprocess +import requests +import folder_paths +from folder_paths import add_model_folder_path, get_filename_list, get_folder_paths +from tqdm import tqdm + +ag_path = os.path.join(os.path.dirname(__file__)) + +def get_python_files(path): + return [f[:-3] for f in os.listdir(path) if f.endswith(".py")] + +def append_to_sys_path(path): + if path not in sys.path: + sys.path.append(path) + +paths = ["comfy-nodes"] +files = [] + +for path in paths: + full_path = os.path.join(ag_path, path) + append_to_sys_path(full_path) + files.extend(get_python_files(full_path)) + +NODE_CLASS_MAPPINGS = {} +NODE_DISPLAY_NAME_MAPPINGS = {} + +# Import all the modules and append their mappings +for file in files: + module = importlib.import_module(file) + + if hasattr(module, "NODE_CLASS_MAPPINGS"): + NODE_CLASS_MAPPINGS.update(module.NODE_CLASS_MAPPINGS) + if hasattr(module, "NODE_DISPLAY_NAME_MAPPINGS"): + NODE_DISPLAY_NAME_MAPPINGS.update(module.NODE_DISPLAY_NAME_MAPPINGS) + +WEB_DIRECTORY = "web-plugin" +__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"] diff --git a/bun.lockb b/bun.lockb deleted file mode 100755 index 30bf970e8dcd6591c2c4f238f19bbbd51111baad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 134273 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 - {children} - - ) -} diff --git a/src/app/page.tsx b/src/app/page.tsx deleted file mode 100644 index b973266..0000000 --- a/src/app/page.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import Image from 'next/image' - -export default function Home() { - return ( -
-
-

- Get started by editing  - src/app/page.tsx -

- -
- -
- Next.js Logo -
- - -
- ) -} diff --git a/tailwind.config.ts b/tailwind.config.ts deleted file mode 100644 index 1af3b8f..0000000 --- a/tailwind.config.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { Config } from 'tailwindcss' - -const config: Config = { - content: [ - './src/pages/**/*.{js,ts,jsx,tsx,mdx}', - './src/components/**/*.{js,ts,jsx,tsx,mdx}', - './src/app/**/*.{js,ts,jsx,tsx,mdx}', - ], - theme: { - extend: { - backgroundImage: { - 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', - 'gradient-conic': - 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', - }, - }, - }, - plugins: [], -} -export default config diff --git a/web-plugin/api.js b/web-plugin/api.js new file mode 100644 index 0000000..f152d28 --- /dev/null +++ b/web-plugin/api.js @@ -0,0 +1,4 @@ +/** @typedef {import('../../../web/scripts/api.js').api} API*/ +import { api as _api } from '../../scripts/api.js'; +/** @type {API} */ +export const api = _api; diff --git a/web-plugin/app.js b/web-plugin/app.js new file mode 100644 index 0000000..53ccc05 --- /dev/null +++ b/web-plugin/app.js @@ -0,0 +1,4 @@ +/** @typedef {import('../../../web/scripts/app.js').ComfyApp} ComfyApp*/ +import { app as _app } from '../../scripts/app.js'; +/** @type {ComfyApp} */ +export const app = _app; diff --git a/web-plugin/index.js b/web-plugin/index.js new file mode 100644 index 0000000..7bca115 --- /dev/null +++ b/web-plugin/index.js @@ -0,0 +1,214 @@ +import { app } from "./app.js"; +import { api } from "./api.js"; +import { ComfyWidgets, LGraphNode } from "./widgets.js"; + +/** @typedef {import('../../../web/types/comfy.js').ComfyExtension} ComfyExtension*/ +/** @type {ComfyExtension} */ +const ext = { + name: "BennyKok.ComfyDeploy", + + init(app) { + addButton(); + }, + + registerCustomNodes() { + /** @type {LGraphNode}*/ + class ComfyDeploy { + color = LGraphCanvas.node_colors.yellow.color; + bgcolor = LGraphCanvas.node_colors.yellow.bgcolor; + groupcolor = LGraphCanvas.node_colors.yellow.groupcolor; + constructor() { + if (!this.properties) { + this.properties = {}; + this.properties.workflow_name = ""; + this.properties.workflow_id = ""; + } + + ComfyWidgets.STRING( + this, + "workflow_name", + ["", { default: this.properties.workflow_name, multiline: false }], + app, + ); + + ComfyWidgets.STRING( + this, + "workflow_id", + ["", { default: this.properties.workflow_id, multiline: false }], + app, + ); + + // this.widgets.forEach((w) => { + // // w.computeSize = () => [200,10] + // w.computedHeight = 2; + // }) + + this.widgets_start_y = 10; + this.setSize(this.computeSize()); + + // const config = { }; + + // console.log(this); + this.serialize_widgets = true; + this.isVirtualNode = true; + } + } + + // Load default visibility + + LiteGraph.registerNodeType( + "Comfy Deploy", + Object.assign(ComfyDeploy, { + title_mode: LiteGraph.NORMAL_TITLE, + title: "Comfy Deploy", + collapsable: true, + }), + ); + + ComfyDeploy.category = "deploy"; + }, + + async setup() { + // const graphCanvas = document.getElementById("graph-canvas"); + + window.addEventListener("message", (event) => { + if (!event.data.flow || Object.entries(event.data.flow).length <= 0) + return; + // updateBlendshapesPrompts(event.data.flow); + }); + + api.addEventListener("executed", (evt) => { + const images = evt.detail?.output.images; + // if (images?.length > 0 && images[0].type === "output") { + // generatedImages[evt.detail.node] = images[0].filename; + // } + // if (evt.detail?.output.gltfFilename) { + + // } + }); + }, +}; + +/** + * @typedef {import('../../../web/types/litegraph.js').LGraph} LGraph + * @typedef {import('../../../web/types/litegraph.js').LGraphNode} LGraphNode + */ + +function addButton() { + const menu = document.querySelector(".comfy-menu"); + + const deploy = document.createElement("button"); + deploy.textContent = "Deploy"; + deploy.className = "sharebtn"; + deploy.onclick = async () => { + /** @type {LGraph} */ + const graph = app.graph; + + const deployMeta = graph.findNodesByType("Comfy Deploy"); + const deployMetaNode = deployMeta[0]; + + console.log(deployMetaNode); + + const workflow_name = deployMetaNode.widgets[0].value; + const workflow_id = deployMetaNode.widgets[1].value; + + console.log(workflow_name, workflow_id); + + const prompt = await app.graphToPrompt(); + console.log(graph); + console.log(prompt); + + deploy.textContent = "Deploying..."; + deploy.style.color = "orange"; + + const apiRoute = "http://localhost:3001/api/upload"; + const userId = "user_2ZA6vuKD3IJXju16oJVQGLBcWwg"; + try { + let data = await fetch(apiRoute, { + method: "POST", + body: JSON.stringify({ + user_id: userId, + workflow_name, + workflow_id, + workflow: prompt.workflow, + workflow_api: prompt.output, + }), + headers: { + "Content-Type": "application/json", + }, + }); + + console.log(data); + + if (data.status !== 200) { + throw new Error(await data.text()); + } else { + data = await data.json(); + } + + deploy.textContent = "Done"; + deploy.style.color = "green"; + + deployMetaNode.widgets[1].value = data.workflow_id; + graph.change(); + + infoDialog.show( + `Deployed successfully!

Workflow ID: ${data.workflow_id}
Workflow Name: ${workflow_name}
Workflow Version: ${data.version}`, + ); + + setTimeout(() => { + deploy.textContent = "Deploy"; + deploy.style.color = "white"; + }, 1000); + } catch (e) { + app.ui.dialog.show(e); + console.error(e); + deploy.textContent = "Error"; + deploy.style.color = "red"; + setTimeout(() => { + deploy.textContent = "Deploy"; + deploy.style.color = "white"; + }, 1000); + } + }; + + menu.append(deploy); +} + +app.registerExtension(ext); + + +import { ComfyDialog, $el } from '../../scripts/ui.js'; + +export class InfoDialog extends ComfyDialog { + constructor() { + super(); + this.element.classList.add("comfy-normal-modal"); + } + createButtons() { + return [ + $el("button", { + type: "button", + textContent: "Close", + onclick: () => this.close(), + }), + ]; + } + + close() { + this.element.style.display = "none"; + } + + show(html) { + this.textElement.style.color = "white"; + if (typeof html === "string") { + this.textElement.innerHTML = html; + } else { + this.textElement.replaceChildren(html); + } + this.element.style.display = "flex"; + this.element.style.zIndex = 1001; + } +} + +export const infoDialog = new InfoDialog() \ No newline at end of file diff --git a/web-plugin/widgets.js b/web-plugin/widgets.js new file mode 100644 index 0000000..a5bd3cf --- /dev/null +++ b/web-plugin/widgets.js @@ -0,0 +1,18 @@ +// /** @typedef {import('../../../web/scripts/api.js').api} API*/ +// import { api as _api } from "../../scripts/api.js"; +// /** @type {API} */ +// export const api = _api; + +/** @typedef {typeof import('../../../web/scripts/widgets.js').ComfyWidgets} Widgets*/ +import { ComfyWidgets as _ComfyWidgets } from "../../scripts/widgets.js"; + +/** + * @type {Widgets} + */ +export const ComfyWidgets = _ComfyWidgets; + +// import { LGraphNode as _LGraphNode } from "../../types/litegraph.js"; + +/** @typedef {typeof import('../../../web/types/litegraph.js').LGraphNode} LGraphNode*/ +/** @type {LGraphNode}*/ +export const LGraphNode = LiteGraph.LGraphNode; diff --git a/web/.eslintignore b/web/.eslintignore new file mode 100644 index 0000000..8fe11da --- /dev/null +++ b/web/.eslintignore @@ -0,0 +1,6 @@ +node_modules +**/node_modules +**/.next +**/public +packages/prisma/zod +apps/web/public/embed diff --git a/web/.eslintrc.js b/web/.eslintrc.js new file mode 100644 index 0000000..706f9e8 --- /dev/null +++ b/web/.eslintrc.js @@ -0,0 +1,94 @@ +/** @type {import("eslint").Linter.Config} */ +module.exports = { + root: true, + extends: [ + // "plugin:playwright/playwright-test", + "next", + "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", + // }, + // }, + ], +}; diff --git a/web/.gitignore b/web/.gitignore new file mode 100644 index 0000000..fd3dbb5 --- /dev/null +++ b/web/.gitignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/README.md b/web/README.md similarity index 100% rename from README.md rename to web/README.md diff --git a/web/bun.lockb b/web/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..6e02745d6293761bfbda29a521ce224e930e5468 GIT binary patch literal 278816 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

K~w6VYWzU5|r129$vs~vjV5e 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 LgS@`K>EHhWgL6dG literal 0 HcmV?d00001 diff --git a/web/components.json b/web/components.json new file mode 100644 index 0000000..e4e8e1a --- /dev/null +++ b/web/components.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/app/globals.css", + "baseColor": "slate", + "cssVariables": true + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils" + } +} \ No newline at end of file diff --git a/web/docker-compose.yml b/web/docker-compose.yml new file mode 100644 index 0000000..8cce5eb --- /dev/null +++ b/web/docker-compose.yml @@ -0,0 +1,22 @@ +# this file is a helper to run Cal.com locally +# starts a postgres instance on port 5460 to use as a local db +version: "3.6" +services: + 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 \ No newline at end of file diff --git a/web/drizzle.config.ts b/web/drizzle.config.ts new file mode 100644 index 0000000..9e8a158 --- /dev/null +++ b/web/drizzle.config.ts @@ -0,0 +1,15 @@ +import type { Config } from 'drizzle-kit'; +import { config } from 'dotenv'; + +config({ + path: `.env.local`, +}); + +export default { + schema: './src/db/schema.ts', + driver: 'pg', + out: './drizzle', + dbCredentials: { + connectionString: (process.env.POSTGRES_URL as string) + ( process.env.POSTGRES_SSL !== "false" ? '?ssl=true' : ""), + }, +} satisfies Config; diff --git a/web/drizzle/0000_quiet_ulik.sql b/web/drizzle/0000_quiet_ulik.sql new file mode 100644 index 0000000..04f02cb --- /dev/null +++ b/web/drizzle/0000_quiet_ulik.sql @@ -0,0 +1,75 @@ +CREATE SCHEMA "comfy_deploy"; +--> statement-breakpoint +DO $$ BEGIN + CREATE TYPE "workflow_run_status" AS ENUM('not-started', 'running', 'success', 'failed'); +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "comfy_deploy"."machines" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "user_id" uuid, + "name" text NOT NULL, + "endpoint" text NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "comfy_deploy"."users" ( + "id" text PRIMARY KEY NOT NULL, + "username" text NOT NULL, + "name" text NOT NULL, + "created_at" timestamp DEFAULT now(), + "updated_at" timestamp DEFAULT now() +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "comfy_deploy"."workflow_runs" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "workflow_version_id" uuid NOT NULL, + "machine_id" uuid NOT NULL, + "status" "workflow_run_status" DEFAULT 'not-started' NOT NULL, + "ended_at" timestamp, + "created_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "comfy_deploy"."workflows" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "user_id" text NOT NULL, + "name" text NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "comfy_deploy"."workflow_versions" ( + "workflow_id" uuid NOT NULL, + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "workflow" jsonb, + "workflow_api" jsonb, + "version" integer NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "comfy_deploy"."workflow_runs" ADD CONSTRAINT "workflow_runs_workflow_version_id_workflow_versions_id_fk" FOREIGN KEY ("workflow_version_id") REFERENCES "comfy_deploy"."workflow_versions"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "comfy_deploy"."workflow_runs" ADD CONSTRAINT "workflow_runs_machine_id_machines_id_fk" FOREIGN KEY ("machine_id") REFERENCES "comfy_deploy"."machines"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "comfy_deploy"."workflows" ADD CONSTRAINT "workflows_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "comfy_deploy"."users"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "comfy_deploy"."workflow_versions" ADD CONSTRAINT "workflow_versions_workflow_id_workflows_id_fk" FOREIGN KEY ("workflow_id") REFERENCES "comfy_deploy"."workflows"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; diff --git a/web/drizzle/0001_silly_arachne.sql b/web/drizzle/0001_silly_arachne.sql new file mode 100644 index 0000000..781fa51 --- /dev/null +++ b/web/drizzle/0001_silly_arachne.sql @@ -0,0 +1,6 @@ +ALTER TABLE "comfy_deploy"."machines" ALTER COLUMN "user_id" SET DATA TYPE text;--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "comfy_deploy"."machines" ADD CONSTRAINT "machines_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "comfy_deploy"."users"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; diff --git a/web/drizzle/0002_clean_khan.sql b/web/drizzle/0002_clean_khan.sql new file mode 100644 index 0000000..6a145bb --- /dev/null +++ b/web/drizzle/0002_clean_khan.sql @@ -0,0 +1 @@ +ALTER TABLE "comfy_deploy"."machines" ALTER COLUMN "user_id" SET NOT NULL; \ No newline at end of file diff --git a/web/drizzle/meta/0000_snapshot.json b/web/drizzle/meta/0000_snapshot.json new file mode 100644 index 0000000..d3f8153 --- /dev/null +++ b/web/drizzle/meta/0000_snapshot.json @@ -0,0 +1,320 @@ +{ + "id": "c9cde314-1f93-4e4c-a010-e31a1edd4cee", + "prevId": "00000000-0000-0000-0000-000000000000", + "version": "5", + "dialect": "pg", + "tables": { + "machines": { + "name": "machines", + "schema": "comfy_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "schema": "comfy_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_runs": { + "name": "workflow_runs", + "schema": "comfy_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": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "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": "no action", + "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": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflows": { + "name": "workflows", + "schema": "comfy_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 + }, + "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": "comfy_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 + }, + "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": { + "workflow_run_status": { + "name": "workflow_run_status", + "values": { + "not-started": "not-started", + "running": "running", + "success": "success", + "failed": "failed" + } + } + }, + "schemas": { + "comfy_deploy": "comfy_deploy" + }, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/web/drizzle/meta/0001_snapshot.json b/web/drizzle/meta/0001_snapshot.json new file mode 100644 index 0000000..6816c77 --- /dev/null +++ b/web/drizzle/meta/0001_snapshot.json @@ -0,0 +1,334 @@ +{ + "id": "3f100d2d-1d9c-46fb-8914-6e8c5a228142", + "prevId": "c9cde314-1f93-4e4c-a010-e31a1edd4cee", + "version": "5", + "dialect": "pg", + "tables": { + "machines": { + "name": "machines", + "schema": "comfy_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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()" + } + }, + "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": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "schema": "comfy_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_runs": { + "name": "workflow_runs", + "schema": "comfy_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": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "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": "no action", + "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": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflows": { + "name": "workflows", + "schema": "comfy_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 + }, + "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": "comfy_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 + }, + "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": { + "workflow_run_status": { + "name": "workflow_run_status", + "values": { + "not-started": "not-started", + "running": "running", + "success": "success", + "failed": "failed" + } + } + }, + "schemas": { + "comfy_deploy": "comfy_deploy" + }, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/web/drizzle/meta/0002_snapshot.json b/web/drizzle/meta/0002_snapshot.json new file mode 100644 index 0000000..e9a4e4f --- /dev/null +++ b/web/drizzle/meta/0002_snapshot.json @@ -0,0 +1,334 @@ +{ + "id": "a5fcd4b7-d6f7-4fcc-a826-0d4ed8d3c7dc", + "prevId": "3f100d2d-1d9c-46fb-8914-6e8c5a228142", + "version": "5", + "dialect": "pg", + "tables": { + "machines": { + "name": "machines", + "schema": "comfy_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 + }, + "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()" + } + }, + "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": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "schema": "comfy_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_runs": { + "name": "workflow_runs", + "schema": "comfy_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": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "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": "no action", + "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": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflows": { + "name": "workflows", + "schema": "comfy_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 + }, + "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": "comfy_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 + }, + "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": { + "workflow_run_status": { + "name": "workflow_run_status", + "values": { + "not-started": "not-started", + "running": "running", + "success": "success", + "failed": "failed" + } + } + }, + "schemas": { + "comfy_deploy": "comfy_deploy" + }, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/web/drizzle/meta/_journal.json b/web/drizzle/meta/_journal.json new file mode 100644 index 0000000..59e0c91 --- /dev/null +++ b/web/drizzle/meta/_journal.json @@ -0,0 +1,27 @@ +{ + "version": "5", + "dialect": "pg", + "entries": [ + { + "idx": 0, + "version": "5", + "when": 1702033790765, + "tag": "0000_quiet_ulik", + "breakpoints": true + }, + { + "idx": 1, + "version": "5", + "when": 1702034015507, + "tag": "0001_silly_arachne", + "breakpoints": true + }, + { + "idx": 2, + "version": "5", + "when": 1702044546478, + "tag": "0002_clean_khan", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/web/migrate.mts b/web/migrate.mts new file mode 100644 index 0000000..d989afe --- /dev/null +++ b/web/migrate.mts @@ -0,0 +1,41 @@ +const { drizzle } = await import("drizzle-orm/postgres-js"); +const { migrate } = await import("drizzle-orm/postgres-js/migrator"); +const { default: postgres } = await import("postgres"); + +import { config } from "dotenv"; +config({ + path: ".local.env", +}); + +const migrationsFolderName = process.env.MIGRATIONS_FOLDER || "drizzle"; +let sslMode: string | boolean = process.env.SSL || "require"; + +if (sslMode === "false") sslMode = false; + +console.log(migrationsFolderName, sslMode); + +const connectionString = process.env.POSTGRES_URL!; +console.log(connectionString); +const sql = postgres(connectionString, { max: 1, ssl: sslMode as any }); +const db = drizzle(sql, { + logger: true, +}); + +let retries = 5; +while(retries) { + try { + await sql`SELECT NOW()`; + console.log('Database is live'); + break; + } catch (error) { + console.error('Database is not live yet', error); + retries -= 1; + console.log(`Retries left: ${retries}`); + await new Promise(res => setTimeout(res, 1000)); + } +} + +console.log("Migrating..."); +await migrate(db, { migrationsFolder: migrationsFolderName }); +console.log("Done!"); +process.exit(); diff --git a/next.config.js b/web/next.config.js similarity index 100% rename from next.config.js rename to web/next.config.js diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..9ff1693 --- /dev/null +++ b/web/package.json @@ -0,0 +1,66 @@ +{ + "name": "comfy-deploy", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "dev:all": "concurrently \"bun run db-up\" \"bun run migrate-local\" \"next dev\"", + "build": "next build", + "start": "next start", + "lint": "next lint", + "generate": "bunx drizzle-kit generate:pg", + "migrate-production": "cp .env.local .env.local.bak && vercel env pull --environment=production && bun run migrate.mts && mv .env.local.bak .env.local", + "migrate-local": "SSL=false LOCAL=true bun run migrate.mts", + "db-up": "docker-compose up", + "db-dev": "bun run db-up && bun run migrate-local" + }, + "dependencies": { + "@clerk/nextjs": "^4.27.4", + "@hookform/resolvers": "^3.3.2", + "@neondatabase/serverless": "^0.6.0", + "@radix-ui/react-checkbox": "^1.0.4", + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-dropdown-menu": "^2.0.6", + "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-select": "^2.0.0", + "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-tabs": "^1.0.4", + "@tanstack/react-table": "^8.10.7", + "class-variance-authority": "^0.7.0", + "clsx": "^2.0.0", + "dayjs": "^1.11.10", + "drizzle-orm": "^0.29.1", + "eslint-config-next": "14.0.3", + "eslint-config-prettier": "^8.6.0", + "eslint-config-turbo": "latest", + "eslint-plugin-prettier": "4.2.1", + "lucide-react": "^0.294.0", + "next": "14.0.3", + "prettier-plugin-tailwindcss": "0.2.5", + "react": "^18", + "react-dom": "^18", + "react-hook-form": "^7.48.2", + "tailwind-merge": "^2.1.0", + "tailwindcss-animate": "^1.0.7", + "zod": "^3.22.4" + }, + "devDependencies": { + "@trivago/prettier-plugin-sort-imports": "4.1.1", + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "@typescript-eslint/eslint-plugin": "^6.13.2", + "@typescript-eslint/parser": "^6.13.2", + "autoprefixer": "^10.0.1", + "concurrently": "^8.2.2", + "dotenv": "^16.3.1", + "drizzle-kit": "^0.20.6", + "eslint": "8.34.0", + "eslint-plugin-unused-imports": "^3.0.0", + "postcss": "^8", + "postgres": "^3.4.3", + "prettier": "2.8.6", + "tailwindcss": "^3.3.0", + "typescript": "^5" + } +} \ No newline at end of file diff --git a/postcss.config.js b/web/postcss.config.js similarity index 96% rename from postcss.config.js rename to web/postcss.config.js index 33ad091..12a703d 100644 --- a/postcss.config.js +++ b/web/postcss.config.js @@ -3,4 +3,4 @@ module.exports = { tailwindcss: {}, autoprefixer: {}, }, -} +}; diff --git a/web/prettier-preset.js b/web/prettier-preset.js new file mode 100644 index 0000000..91fa034 --- /dev/null +++ b/web/prettier-preset.js @@ -0,0 +1,39 @@ +module.exports = { + bracketSpacing: true, + bracketSameLine: true, + singleQuote: false, + jsxSingleQuote: false, + trailingComma: "es5", + semi: true, + printWidth: 110, + arrowParens: "always", + endOfLine: "auto", + importOrder: [ + // Mocks must be at the top as they contain vi.mock calls + "(.*)/__mocks__/(.*)", + "", + "^@(calcom|ee)/(.*)$", + "^@lib/(.*)$", + "^@components/(.*)$", + "^@(server|trpc)/(.*)$", + "^~/(.*)$", + "^[./]", + ], + importOrderSeparation: true, + plugins: [ + "@trivago/prettier-plugin-sort-imports", + /** + * **NOTE** tailwind plugin must come last! + * @see https://github.com/tailwindlabs/prettier-plugin-tailwindcss#compatibility-with-other-prettier-plugins + */ + "prettier-plugin-tailwindcss", + ], + // overrides: [ + // { + // files: ["apps/website/lib/utils/wordlist/wordlist.ts"], + // options: { + // quoteProps: "consistent", + // }, + // }, + // ], +}; diff --git a/public/next.svg b/web/public/next.svg similarity index 100% rename from public/next.svg rename to web/public/next.svg diff --git a/public/vercel.svg b/web/public/vercel.svg similarity index 100% rename from public/vercel.svg rename to web/public/vercel.svg diff --git a/web/src/app/[workflow_id]/page.tsx b/web/src/app/[workflow_id]/page.tsx new file mode 100644 index 0000000..0b3d669 --- /dev/null +++ b/web/src/app/[workflow_id]/page.tsx @@ -0,0 +1,64 @@ +import { MachineSelect, VersionSelect } from "@/components/VersionSelect"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { db } from "@/db/db"; +import { workflowTable, workflowVersionTable } from "@/db/schema"; +import { getRelativeTime } from "@/lib/getRelativeTime"; +import { getMachines } from "@/server/curdMachine"; +import { desc, eq, sql } from "drizzle-orm"; +import { Play } from "lucide-react"; + +export async function findFirstTableWithVersion(workflow_id: string) { + return await db.query.workflowTable.findFirst({ + with: { versions: { orderBy: desc(workflowVersionTable.version) } }, + where: eq(workflowTable.id, workflow_id), + }); +} + +export default async function Page({ + params, +}: { + params: { workflow_id: string }; +}) { + const workflow_id = params.workflow_id; + + const workflow = await findFirstTableWithVersion(workflow_id); + const machines = await getMachines(); + + return ( +

+ ); +} diff --git a/web/src/app/api/create-run/route.ts b/web/src/app/api/create-run/route.ts new file mode 100644 index 0000000..0ea8c3b --- /dev/null +++ b/web/src/app/api/create-run/route.ts @@ -0,0 +1,56 @@ +import { parseDataSafe } from "../../../lib/parseDataSafe"; +import { db } from "@/db/db"; +import { + workflowRunStatus, + workflowRunsTable, + workflowTable, + workflowVersionTable, +} from "@/db/schema"; +import { eq, sql } from "drizzle-orm"; +import { NextResponse } from "next/server"; +import { ZodFormattedError, z } from "zod"; + +const Request = z.object({ + workflow_version_id: z.string(), + machine_id: z.string(), +}); + +export async function OPTIONS(request: Request) { + return new Response(null, { + status: 204, + headers: { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type, Authorization", + }, + }); +} + +export async function POST(request: Request) { + const [data, error] = await parseDataSafe(Request, request); + if (!data || error) return error; + + let { workflow_version_id, machine_id } = data; + + const workflow_run = await db + .insert(workflowRunsTable) + .values({ + workflow_version_id, + machine_id, + }) + .returning(); + + return NextResponse.json( + { + workflow_run_id: workflow_run[0].id, + }, + { + status: 200, + headers: { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type, Authorization", + }, + }, + ); +} diff --git a/web/src/app/api/update-run/route.ts b/web/src/app/api/update-run/route.ts new file mode 100644 index 0000000..b5c003a --- /dev/null +++ b/web/src/app/api/update-run/route.ts @@ -0,0 +1,55 @@ +import { parseDataSafe } from "../../../lib/parseDataSafe"; +import { db } from "@/db/db"; +import { + workflowRunStatus, + workflowRunsTable, + workflowTable, + workflowVersionTable, +} from "@/db/schema"; +import { eq, sql } from "drizzle-orm"; +import { NextResponse } from "next/server"; +import { ZodFormattedError, z } from "zod"; + +const Request = z.object({ + run_id: z.string(), + status: z.enum(["not-started", "running", "success", "failed"]), +}); + +export async function OPTIONS(request: Request) { + return new Response(null, { + status: 204, + headers: { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type, Authorization", + }, + }); +} + +export async function POST(request: Request) { + const [data, error] = await parseDataSafe(Request, request); + if (!data || error) return error; + + let { run_id, status } = data; + + const workflow_run = await db + .update(workflowRunsTable) + .set({ + status: status, + }) + .where(eq(workflowRunsTable.id, run_id)); + + return NextResponse.json( + { + message: "success", + }, + { + status: 200, + headers: { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type, Authorization", + }, + }, + ); +} diff --git a/web/src/app/api/upload/route.ts b/web/src/app/api/upload/route.ts new file mode 100644 index 0000000..c27be52 --- /dev/null +++ b/web/src/app/api/upload/route.ts @@ -0,0 +1,125 @@ +import { parseDataSafe } from "../../../lib/parseDataSafe"; +import { db } from "@/db/db"; +import { workflowTable, workflowVersionTable } from "@/db/schema"; +import { eq, sql } from "drizzle-orm"; +import { NextResponse } from "next/server"; +import { ZodFormattedError, z } from "zod"; + +const corsHeaders = { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type, Authorization", +}; + +const UploadRequest = z.object({ + user_id: z.string(), + workflow_id: z.string().optional(), + workflow_name: z.string().optional(), + workflow: z.any(), + workflow_api: z.any(), +}); + +export async function OPTIONS(request: Request) { + return new Response(null, { + status: 204, + headers: { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type, Authorization", + }, + }); +} + +export async function POST(request: Request) { + console.log("hi"); + + const [data, error] = await parseDataSafe( + UploadRequest, + request, + corsHeaders, + ); + + if (!data || error) return error; + + let { user_id, workflow, workflow_api, workflow_id, workflow_name } = data; + + let version = -1; + + // Case 1 new workflow + try { + if ((!workflow_id || workflow_id.length == 0) && workflow_name) { + // Create a new parent workflow + const workflow = await db + .insert(workflowTable) + .values({ + user_id, + name: workflow_name, + }) + .returning(); + + workflow_id = workflow[0].id; + + // Create a new version + const data = await db + .insert(workflowVersionTable) + .values({ + workflow_id: workflow_id, + workflow, + workflow_api, + version: 1, + }) + .returning(); + version = data[0].version; + } else if (workflow_id) { + // Case 2 update workflow + const data = await db + .insert(workflowVersionTable) + .values({ + workflow_id, + workflow, + workflow_api, + // version: sql`${workflowVersionTable.version} + 1`, + version: sql`( + SELECT COALESCE(MAX(version), 0) + 1 + FROM ${workflowVersionTable} + WHERE workflow_id = ${workflow_id} + )`, + }) + .returning(); + version = data[0].version; + } else { + return NextResponse.json( + { + error: "Invalid request, missing either workflow_id or name", + }, + { + status: 500, + statusText: "Invalid request", + headers: corsHeaders, + }, + ); + } + } catch (error: any) { + return NextResponse.json( + { + error: error.toString(), + }, + { + status: 500, + statusText: "Invalid request", + headers: corsHeaders, + }, + ); + } + + return NextResponse.json( + { + workflow_id: workflow_id, + version: version, + }, + { + status: 200, + headers: corsHeaders, + }, + ); +} diff --git a/src/app/favicon.ico b/web/src/app/favicon.ico similarity index 100% rename from src/app/favicon.ico rename to web/src/app/favicon.ico diff --git a/web/src/app/globals.css b/web/src/app/globals.css new file mode 100644 index 0000000..6a75725 --- /dev/null +++ b/web/src/app/globals.css @@ -0,0 +1,76 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.9%; + + --radius: 0.5rem; + } + + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 83.9%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} \ No newline at end of file diff --git a/web/src/app/layout.tsx b/web/src/app/layout.tsx new file mode 100644 index 0000000..f48e631 --- /dev/null +++ b/web/src/app/layout.tsx @@ -0,0 +1,36 @@ +import "./globals.css"; +import { NavbarRight } from "@/components/NavbarRight"; +import type { Metadata } from "next"; +import { Inter } from "next/font/google"; + +const inter = Inter({ subsets: ["latin"] }); + +export const metadata: Metadata = { + title: "Comfy Deploy", + description: "Generated by create next app", +}; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + +
+ +
+ {children} +
+
+ + + ); +} diff --git a/web/src/app/machines/page.tsx b/web/src/app/machines/page.tsx new file mode 100644 index 0000000..126b2af --- /dev/null +++ b/web/src/app/machines/page.tsx @@ -0,0 +1,67 @@ +import { MachineList } from "@/components/MachineList"; +import { WorkflowList } from "@/components/WorkflowList"; +import { db } from "@/db/db"; +import { + machinesTable, + usersTable, + workflowTable, + workflowVersionTable, +} from "@/db/schema"; +import { auth, clerkClient } from "@clerk/nextjs"; +import { desc, eq, sql } from "drizzle-orm"; + +export default function Page() { + return ; +} + +async function MachineListServer() { + const { userId } = await auth(); + + if (!userId) { + return
No auth
; + } + + const workflow = await db.query.machinesTable.findMany({ + orderBy: desc(machinesTable.updated_at), + where: eq(machinesTable.user_id, userId), + }); + + return ( +
+ {/*
Machines
*/} + { + return { + id: x.id, + name: x.name, + date: x.updated_at, + endpoint: x.endpoint, + }; + })} + /> +
+ ); +} + +async function setInitialUserData(userId: string) { + const user = await clerkClient.users.getUser(userId); + + // incase we dont have username such as google login, fallback to first name + last name + const usernameFallback = + user.username ?? (user.firstName ?? "") + (user.lastName ?? ""); + + // For the display name, if it for some reason is empty, fallback to username + let nameFallback = (user.firstName ?? "") + (user.lastName ?? ""); + if (nameFallback === "") { + nameFallback = usernameFallback; + } + + const result = await db.insert(usersTable).values({ + id: userId, + // this is used for path, make sure this is unique + username: usernameFallback, + + // this is for display name, maybe different from username + name: nameFallback, + }); +} diff --git a/web/src/app/page.tsx b/web/src/app/page.tsx new file mode 100644 index 0000000..1ceb9a4 --- /dev/null +++ b/web/src/app/page.tsx @@ -0,0 +1,77 @@ +import { WorkflowList } from "@/components/WorkflowList"; +import { db } from "@/db/db"; +import { usersTable, workflowTable, workflowVersionTable } from "@/db/schema"; +import { auth, clerkClient } from "@clerk/nextjs"; +import { desc, eq, sql } from "drizzle-orm"; + +export default function Home() { + return ; +} + +async function WorkflowServer() { + const { userId } = await auth(); + + if (!userId) { + return
No auth
; + } + + const user = await db.query.usersTable.findFirst({ + where: eq(usersTable.id, userId), + }); + + if (!user) { + await setInitialUserData(userId); + } + + const workflow = await db.query.workflowTable.findMany({ + // extras: { + // count: sql`(select count(*) from ${workflowVersionTable})`.as( + // "count", + // ), + // }, + with: { + versions: { + limit: 1, + orderBy: desc(workflowVersionTable.version), + }, + }, + orderBy: desc(workflowTable.updated_at), + where: eq(workflowTable.user_id, userId), + }); + + return ( + { + return { + id: x.id, + email: x.name, + amount: x.versions[0]?.version ?? 0, + date: x.updated_at, + }; + })} + /> + ); +} + +async function setInitialUserData(userId: string) { + const user = await clerkClient.users.getUser(userId); + + // incase we dont have username such as google login, fallback to first name + last name + const usernameFallback = + user.username ?? (user.firstName ?? "") + (user.lastName ?? ""); + + // For the display name, if it for some reason is empty, fallback to username + let nameFallback = (user.firstName ?? "") + (user.lastName ?? ""); + if (nameFallback === "") { + nameFallback = usernameFallback; + } + + const result = await db.insert(usersTable).values({ + id: userId, + // this is used for path, make sure this is unique + username: usernameFallback, + + // this is for display name, maybe different from username + name: nameFallback, + }); +} diff --git a/web/src/components/MachineList.tsx b/web/src/components/MachineList.tsx new file mode 100644 index 0000000..67b3556 --- /dev/null +++ b/web/src/components/MachineList.tsx @@ -0,0 +1,425 @@ +"use client"; + +import { getRelativeTime } from "../lib/getRelativeTime"; +import { + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, + Form, +} from "./ui/form"; +import { Button } from "@/components/ui/button"; +import { Checkbox } from "@/components/ui/checkbox"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { addMachine, deleteMachine } from "@/server/curdMachine"; +import { deleteWorkflow } from "@/server/deleteWorkflow"; +import { zodResolver } from "@hookform/resolvers/zod"; +import type { + ColumnDef, + ColumnFiltersState, + SortingState, + VisibilityState, +} from "@tanstack/react-table"; +import { + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table"; +import { + ArrowUpDown, + ChevronDown, + LoaderIcon, + MoreHorizontal, +} from "lucide-react"; +import * as React from "react"; +import { useFormStatus } from "react-dom"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; + +export type Machine = { + id: string; + name: string; + endpoint: string; + date: Date; +}; + +export const columns: ColumnDef[] = [ + { + accessorKey: "id", + id: "select", + header: ({ table }) => ( + table.toggleAllPageRowsSelected(!!value)} + aria-label="Select all" + /> + ), + cell: ({ row }) => ( + row.toggleSelected(!!value)} + aria-label="Select row" + /> + ), + enableSorting: false, + enableHiding: false, + }, + { + accessorKey: "name", + header: ({ column }) => { + return ( + + ); + }, + cell: ({ row }) => { + return ( + // + row.getValue("name") + // + ); + }, + }, + { + accessorKey: "endpoint", + header: () =>
Endpoint
, + cell: ({ row }) => { + return ( +
{row.original.endpoint}
+ ); + }, + }, + { + accessorKey: "date", + sortingFn: "datetime", + enableSorting: true, + header: ({ column }) => { + return ( + + ); + }, + cell: ({ row }) => ( +
{getRelativeTime(row.original.date)}
+ ), + }, + + { + id: "actions", + enableHiding: false, + cell: ({ row }) => { + const workflow = row.original; + + return ( + + + + + + Actions + { + deleteMachine(workflow.id); + // navigator.clipboard.writeText(payment.id) + }} + > + Delete Machine + + {/* + View customer + View payment details */} + + + ); + }, + }, +]; + +export function MachineList({ data }: { data: Machine[] }) { + const [sorting, setSorting] = React.useState([]); + const [columnFilters, setColumnFilters] = React.useState( + [], + ); + const [columnVisibility, setColumnVisibility] = + React.useState({}); + const [rowSelection, setRowSelection] = React.useState({}); + + const table = useReactTable({ + data, + columns, + onSortingChange: setSorting, + onColumnFiltersChange: setColumnFilters, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + getFilteredRowModel: getFilteredRowModel(), + onColumnVisibilityChange: setColumnVisibility, + onRowSelectionChange: setRowSelection, + state: { + sorting, + columnFilters, + columnVisibility, + rowSelection, + }, + }); + + return ( +
+
+ + table.getColumn("name")?.setFilterValue(event.target.value) + } + className="max-w-sm" + /> +
+ + {/* + + + + + {table + .getAllColumns() + .filter((column) => column.getCanHide()) + .map((column) => { + return ( + + column.toggleVisibility(!!value) + } + > + {column.id} + + ); + })} + + */} +
+
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext(), + )} + + ); + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext(), + )} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
+
+
+
+ {table.getFilteredSelectedRowModel().rows.length} of{" "} + {table.getFilteredRowModel().rows.length} row(s) selected. +
+
+ + +
+
+
+ ); +} + +const formSchema = z.object({ + name: z.string().min(1), + endpoint: z.string().min(1), +}); + +function AddMachinesDialog() { + const [open, setOpen] = React.useState(false); + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + name: "", + endpoint: "", + }, + }); + + return ( + + + + + +
+ { + await addMachine(data.name, data.endpoint); + // await new Promise(resolve => setTimeout(resolve, 3000)); + setOpen(false); + })} + > + + Add Machines + + Add Comfyui machines to your account. + + +
+ {/*
*/} + ( + + Name + + + + {/* + This is your public display name. + */} + + + )} + /> + + ( + + Endpoint + + + + {/* + This is your public display name. + */} + + + )} + /> +
+ + + + + + +
+ ); +} + +function AddWorkflowButton({ pending }: { pending: boolean }) { + // const { pending } = useFormStatus(); + return ( + + ); +} diff --git a/web/src/components/NavbarRight.tsx b/web/src/components/NavbarRight.tsx new file mode 100644 index 0000000..91127e9 --- /dev/null +++ b/web/src/components/NavbarRight.tsx @@ -0,0 +1,29 @@ +"use client"; + +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { usePathname } from "next/navigation"; +import { useRouter } from "next/navigation"; + +export function NavbarRight() { + const pathname = usePathname(); + const router = useRouter(); + + return ( + { + if (value === "machines") { + router.push("/machines"); + } else { + router.push("/"); + } + }} + > + + Workflow + Machines + + + ); +} diff --git a/web/src/components/VersionSelect.tsx b/web/src/components/VersionSelect.tsx new file mode 100644 index 0000000..4684e30 --- /dev/null +++ b/web/src/components/VersionSelect.tsx @@ -0,0 +1,63 @@ +"use client"; + +import { findFirstTableWithVersion } from "@/app/[workflow_id]/page"; +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { getMachines } from "@/server/curdMachine"; + +export function VersionSelect({ + workflow, +}: { + workflow: Awaited>; +}) { + return ( + + ); +} + + +export function MachineSelect({ + machines, + }: { + machines: Awaited>; + }) { + return ( + + ); + } + \ No newline at end of file diff --git a/web/src/components/WorkflowList.tsx b/web/src/components/WorkflowList.tsx new file mode 100644 index 0000000..552c10d --- /dev/null +++ b/web/src/components/WorkflowList.tsx @@ -0,0 +1,309 @@ +"use client"; + +import { getRelativeTime } from "../lib/getRelativeTime"; +import { Button } from "@/components/ui/button"; +import { Checkbox } from "@/components/ui/checkbox"; +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Input } from "@/components/ui/input"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { deleteWorkflow } from "@/server/deleteWorkflow"; +import type { + ColumnDef, + ColumnFiltersState, + SortingState, + VisibilityState, +} from "@tanstack/react-table"; +import { + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table"; +import { ArrowUpDown, ChevronDown, MoreHorizontal } from "lucide-react"; +import * as React from "react"; + +export type Payment = { + id: string; + amount: number; + date: Date; + email: string; +}; + +export const columns: ColumnDef[] = [ + { + accessorKey: "id", + id: "select", + header: ({ table }) => ( + table.toggleAllPageRowsSelected(!!value)} + aria-label="Select all" + /> + ), + cell: ({ row }) => ( + row.toggleSelected(!!value)} + aria-label="Select row" + /> + ), + enableSorting: false, + enableHiding: false, + }, + { + accessorKey: "email", + header: ({ column }) => { + return ( + + ); + }, + cell: ({ row }) => { + return ( + + {row.getValue("email")} + + ); + }, + }, + + { + accessorKey: "amount", + header: () =>
Version
, + cell: ({ row }) => { + const amount = parseFloat(row.getValue("amount")); + + // Format the amount as a dollar amount + // const formatted = new Intl.NumberFormat("en-US", { + // style: "currency", + // currency: "USD", + // }).format(amount); + + return
{amount}
; + }, + }, + { + accessorKey: "date", + sortingFn: "datetime", + enableSorting: true, + header: ({ column }) => { + return ( + + ); + }, + cell: ({ row }) => ( +
+ {getRelativeTime(row.original.date)} +
+ ), + }, + { + id: "actions", + enableHiding: false, + cell: ({ row }) => { + const workflow = row.original; + + return ( + + + + + + Actions + { + deleteWorkflow(workflow.id); + // navigator.clipboard.writeText(payment.id) + }} + > + Delete Workflow + + {/* + View customer + View payment details */} + + + ); + }, + }, +]; + +export function WorkflowList({ data }: { data: Payment[] }) { + const [sorting, setSorting] = React.useState([]); + const [columnFilters, setColumnFilters] = React.useState( + [], + ); + const [columnVisibility, setColumnVisibility] = + React.useState({}); + const [rowSelection, setRowSelection] = React.useState({}); + + const table = useReactTable({ + data, + columns, + onSortingChange: setSorting, + onColumnFiltersChange: setColumnFilters, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + getFilteredRowModel: getFilteredRowModel(), + onColumnVisibilityChange: setColumnVisibility, + onRowSelectionChange: setRowSelection, + state: { + sorting, + columnFilters, + columnVisibility, + rowSelection, + }, + }); + + return ( +
+
+ + table.getColumn("email")?.setFilterValue(event.target.value) + } + className="max-w-sm" + /> + + + + + + {table + .getAllColumns() + .filter((column) => column.getCanHide()) + .map((column) => { + return ( + + column.toggleVisibility(!!value) + } + > + {column.id} + + ); + })} + + +
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext(), + )} + + ); + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext(), + )} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
+
+
+
+ {table.getFilteredSelectedRowModel().rows.length} of{" "} + {table.getFilteredRowModel().rows.length} row(s) selected. +
+
+ + +
+
+
+ ); +} diff --git a/web/src/components/ui/button.tsx b/web/src/components/ui/button.tsx new file mode 100644 index 0000000..78fcae9 --- /dev/null +++ b/web/src/components/ui/button.tsx @@ -0,0 +1,55 @@ +import { cn } from "@/lib/utils"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; +import * as React from "react"; + +const buttonVariants = cva( + "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", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-10 px-4 py-2", + 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 + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button"; + return ( + + ); + } +); +Button.displayName = "Button"; + +export { Button, buttonVariants }; diff --git a/web/src/components/ui/card.tsx b/web/src/components/ui/card.tsx new file mode 100644 index 0000000..afa13ec --- /dev/null +++ b/web/src/components/ui/card.tsx @@ -0,0 +1,79 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Card.displayName = "Card" + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardHeader.displayName = "CardHeader" + +const CardTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardTitle.displayName = "CardTitle" + +const CardDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardDescription.displayName = "CardDescription" + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardContent.displayName = "CardContent" + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardFooter.displayName = "CardFooter" + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/web/src/components/ui/checkbox.tsx b/web/src/components/ui/checkbox.tsx new file mode 100644 index 0000000..df61a13 --- /dev/null +++ b/web/src/components/ui/checkbox.tsx @@ -0,0 +1,30 @@ +"use client" + +import * as React from "react" +import * as CheckboxPrimitive from "@radix-ui/react-checkbox" +import { Check } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Checkbox = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + +)) +Checkbox.displayName = CheckboxPrimitive.Root.displayName + +export { Checkbox } diff --git a/web/src/components/ui/dialog.tsx b/web/src/components/ui/dialog.tsx new file mode 100644 index 0000000..cad6f58 --- /dev/null +++ b/web/src/components/ui/dialog.tsx @@ -0,0 +1,122 @@ +"use client" + +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { X } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Dialog = DialogPrimitive.Root + +const DialogTrigger = DialogPrimitive.Trigger + +const DialogPortal = DialogPrimitive.Portal + +const DialogClose = DialogPrimitive.Close + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +DialogContent.displayName = DialogPrimitive.Content.displayName + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogHeader.displayName = "DialogHeader" + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogFooter.displayName = "DialogFooter" + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogTitle.displayName = DialogPrimitive.Title.displayName + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogDescription.displayName = DialogPrimitive.Description.displayName + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogClose, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} diff --git a/web/src/components/ui/dropdown-menu.tsx b/web/src/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..f69a0d6 --- /dev/null +++ b/web/src/components/ui/dropdown-menu.tsx @@ -0,0 +1,200 @@ +"use client" + +import * as React from "react" +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" +import { Check, ChevronRight, Circle } from "lucide-react" + +import { cn } from "@/lib/utils" + +const DropdownMenu = DropdownMenuPrimitive.Root + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger + +const DropdownMenuGroup = DropdownMenuPrimitive.Group + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal + +const DropdownMenuSub = DropdownMenuPrimitive.Sub + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup + +const DropdownMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)) +DropdownMenuSubTrigger.displayName = + DropdownMenuPrimitive.SubTrigger.displayName + +const DropdownMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DropdownMenuSubContent.displayName = + DropdownMenuPrimitive.SubContent.displayName + +const DropdownMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + + + +)) +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName + +const DropdownMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName + +const DropdownMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)) +DropdownMenuCheckboxItem.displayName = + DropdownMenuPrimitive.CheckboxItem.displayName + +const DropdownMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)) +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName + +const DropdownMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName + +const DropdownMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName + +const DropdownMenuShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ) +} +DropdownMenuShortcut.displayName = "DropdownMenuShortcut" + +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuRadioGroup, +} diff --git a/web/src/components/ui/form.tsx b/web/src/components/ui/form.tsx new file mode 100644 index 0000000..4603f8b --- /dev/null +++ b/web/src/components/ui/form.tsx @@ -0,0 +1,176 @@ +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" +import { Slot } from "@radix-ui/react-slot" +import { + Controller, + ControllerProps, + FieldPath, + FieldValues, + FormProvider, + useFormContext, +} from "react-hook-form" + +import { cn } from "@/lib/utils" +import { Label } from "@/components/ui/label" + +const Form = FormProvider + +type FormFieldContextValue< + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath +> = { + name: TName +} + +const FormFieldContext = React.createContext( + {} as FormFieldContextValue +) + +const FormField = < + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath +>({ + ...props +}: ControllerProps) => { + return ( + + + + ) +} + +const useFormField = () => { + const fieldContext = React.useContext(FormFieldContext) + const itemContext = React.useContext(FormItemContext) + const { getFieldState, formState } = useFormContext() + + const fieldState = getFieldState(fieldContext.name, formState) + + if (!fieldContext) { + throw new Error("useFormField should be used within ") + } + + const { id } = itemContext + + return { + id, + name: fieldContext.name, + formItemId: `${id}-form-item`, + formDescriptionId: `${id}-form-item-description`, + formMessageId: `${id}-form-item-message`, + ...fieldState, + } +} + +type FormItemContextValue = { + id: string +} + +const FormItemContext = React.createContext( + {} as FormItemContextValue +) + +const FormItem = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => { + const id = React.useId() + + return ( + +
+ + ) +}) +FormItem.displayName = "FormItem" + +const FormLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => { + const { error, formItemId } = useFormField() + + return ( +