diff --git a/web-plugin/index.js b/web-plugin/index.js
index 5aedf7e..199b460 100644
--- a/web-plugin/index.js
+++ b/web-plugin/index.js
@@ -102,6 +102,12 @@ const ext = {
* @typedef {import('../../../web/types/litegraph.js').LGraphNode} LGraphNode
*/
+function showError(title, message) {
+ infoDialog.show(
+ `
${title}
${message} `,
+ );
+}
+
function addButton() {
const menu = document.querySelector(".comfy-menu");
@@ -113,9 +119,46 @@ function addButton() {
/** @type {LGraph} */
const graph = app.graph;
- const title = deploy.querySelector("#button-title")
+ const snapshot = await fetch("/snapshot/get_current").then((x) => x.json());
+ console.log(snapshot);
+
+ if (!snapshot) {
+ showError(
+ "Error when deploying",
+ "Unable to generate snapshot, please install ComfyUI Manager",
+ );
+ return;
+ }
+
+ const title = deploy.querySelector("#button-title");
+
+ let deployMeta = graph.findNodesByType("ComfyDeploy");
+
+ if (deployMeta.length == 0) {
+ const text = await inputDialog.input(
+ "Create your deployment",
+ "Workflow name",
+ );
+ if (!text) return
+ console.log(text);
+ app.graph.beforeChange();
+ var node = LiteGraph.createNode("ComfyDeploy");
+ node.configure({
+ widgets_values: [
+ text
+ ]
+ });
+ node.pos = [0, 0];
+ app.graph.add(node);
+ app.graph.afterChange();
+ deployMeta=[node]
+ // return;
+ // showError(
+ // "Error when deploying",
+ // "Unable to to find ComfyDeploy node, please add it first.",
+ // );
+ }
- const deployMeta = graph.findNodesByType("ComfyDeploy");
const deployMetaNode = deployMeta[0];
console.log(deployMetaNode);
@@ -132,10 +175,7 @@ function addButton() {
// const endpoint = localStorage.getItem("endpoint") ?? "";
// const apiKey = localStorage.getItem("apiKey");
- const {
- endpoint,
- apiKey,
- } = getData();
+ const { endpoint, apiKey } = getData();
if (!endpoint || !apiKey || apiKey === "" || endpoint === "") {
configDialog.show();
@@ -152,7 +192,7 @@ function addButton() {
endpoint = endpoint.slice(0, -1);
}
- const apiRoute = endpoint + "/api/upload"
+ const apiRoute = endpoint + "/api/upload";
// const userId = apiKey
try {
let data = await fetch(apiRoute, {
@@ -162,10 +202,11 @@ function addButton() {
workflow_id,
workflow: prompt.workflow,
workflow_api: prompt.output,
+ snapshot: snapshot,
}),
headers: {
"Content-Type": "application/json",
- "Authorization": "Bearer " + apiKey,
+ Authorization: "Bearer " + apiKey,
},
});
@@ -185,7 +226,7 @@ function addButton() {
graph.change();
infoDialog.show(
- `Deployed successfully!
Workflow ID: ${data.workflow_id}
Workflow Name: ${workflow_name}
Workflow Version: ${data.version}`,
+ `Deployed successfully! View here ->
Workflow ID: ${data.workflow_id}
Workflow Name: ${workflow_name}
Workflow Version: ${data.version}
`,
);
setTimeout(() => {
@@ -210,19 +251,18 @@ function addButton() {
config.style.position = "absolute";
config.style.right = "10px";
config.style.top = "0px";
-
+
// set aspect ratio to square
config.style.width = "20px";
- config.src = "https://api.iconify.design/material-symbols-light:settings.svg?color=%23888888";
+ config.src =
+ "https://api.iconify.design/material-symbols-light:settings.svg?color=%23888888";
config.onclick = (e) => {
- e.preventDefault()
- e.stopPropagation()
+ e.preventDefault();
+ e.stopPropagation();
configDialog.show();
};
- deploy.append(
- config
- )
+ deploy.append(config);
deploy.style.order = "99";
@@ -231,44 +271,113 @@ function addButton() {
app.registerExtension(ext);
-
-import { ComfyDialog, $el } from '../../scripts/ui.js';
+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(),
- }),
- ];
- }
+ constructor() {
+ super();
+ this.element.classList.add("comfy-normal-modal");
+ this.element.style.paddingBottom = "20px";
+ }
+ createButtons() {
+ return [
+ $el("button", {
+ type: "button",
+ textContent: "Close",
+ onclick: () => this.close(),
+ }),
+ ];
+ }
- close() {
- this.element.style.display = "none";
- }
+ close() {
+ this.element.style.display = "none";
+ }
- show(html) {
+ show(html) {
+ this.textElement.style["white-space"] = "normal";
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;
- }
+ 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;
+ }
}
-export const infoDialog = new InfoDialog()
+export class InputDialog extends InfoDialog {
+ callback = undefined;
+
+ constructor() {
+ super();
+ }
+
+ createButtons() {
+ return [
+ $el(
+ "div",
+ {
+ type: "div",
+ style: {
+ display: "flex",
+ gap: "6px",
+ justifyContent: "flex-end",
+ width: "100%",
+ },
+ },
+ [
+ $el("button", {
+ type: "button",
+ textContent: "Save",
+ onclick: () => {
+ const input = this.textElement.querySelector("#input").value;
+ if (input.trim() === "") {
+ showError("Input validation", "Input cannot be empty");
+ } else {
+ this.callback?.(input);
+ this.close();
+ this.textElement.querySelector("#input").value = "";
+ }
+ },
+ }),
+ $el("button", {
+ type: "button",
+ textContent: "Close",
+ onclick: () => {
+ this.callback?.(undefined);
+ this.close()
+ },
+ }),
+ ],
+ ),
+ ];
+ }
+
+ input(title, message) {
+ return new Promise((resolve, reject) => {
+ this.callback = resolve;
+ this.show(`
+
+
${title}
+
+
+ `);
+ });
+ }
+}
+
+export const inputDialog = new InputDialog();
+
+export const infoDialog = new InfoDialog();
function getData(environment) {
- const deployOption = environment || localStorage.getItem("comfy_deploy_env") || "cloud";
+ const deployOption =
+ environment || localStorage.getItem("comfy_deploy_env") || "cloud";
const data = localStorage.getItem("comfy_deploy_env_data_" + deployOption);
if (!data) {
if (deployOption == "cloud")
@@ -276,7 +385,7 @@ function getData(environment) {
endpoint: "https://www.comfydeploy.com",
apiKey: "",
};
- else
+ else
return {
endpoint: "http://localhost:3000",
apiKey: "",
@@ -289,12 +398,12 @@ function getData(environment) {
}
export class ConfigDialog extends ComfyDialog {
-
container = null;
constructor() {
super();
this.element.classList.add("comfy-normal-modal");
+ this.element.style.paddingBottom = "20px";
this.container = document.createElement("div");
this.element.querySelector(".comfy-modal-content").prepend(this.container);
@@ -302,16 +411,18 @@ export class ConfigDialog extends ComfyDialog {
createButtons() {
return [
- $el("div", {
- type: "div",
- style: {
- display: "flex",
- gap: "6px",
- justifyContent: "flex-end",
- width: "100%",
+ $el(
+ "div",
+ {
+ type: "div",
+ style: {
+ display: "flex",
+ gap: "6px",
+ justifyContent: "flex-end",
+ width: "100%",
+ },
+ onclick: () => this.save(),
},
- onclick: () => this.save(),
- },
[
$el("button", {
type: "button",
@@ -322,8 +433,8 @@ export class ConfigDialog extends ComfyDialog {
type: "button",
textContent: "Close",
onclick: () => this.close(),
- })
- ]
+ }),
+ ],
),
];
}
@@ -341,8 +452,11 @@ export class ConfigDialog extends ComfyDialog {
const data = {
endpoint,
apiKey,
- }
- localStorage.setItem("comfy_deploy_env_data_" + deployOption, JSON.stringify(data));
+ };
+ localStorage.setItem(
+ "comfy_deploy_env_data_" + deployOption,
+ JSON.stringify(data),
+ );
this.close();
}
@@ -350,39 +464,47 @@ export class ConfigDialog extends ComfyDialog {
this.container.style.color = "white";
const data = getData();
-
+
this.container.innerHTML = `
Comfy Deploy Config
`;
const apiKeyInput = this.container.querySelector("#apiKey");
- apiKeyInput.addEventListener("paste", function(e) {
+ apiKeyInput.addEventListener("paste", function (e) {
e.stopPropagation();
});
const deployOption = this.container.querySelector("#deployOption");
- const container = this.container
- deployOption.addEventListener("change", function() {
+ const container = this.container;
+ deployOption.addEventListener("change", function () {
const selectedOption = this.value;
const data = getData(selectedOption);
localStorage.setItem("comfy_deploy_env", selectedOption);
-
+
container.querySelector("#endpoint").value = data.endpoint;
container.querySelector("#apiKey").value = data.apiKey;
});
@@ -392,4 +514,4 @@ export class ConfigDialog extends ComfyDialog {
}
}
-export const configDialog = new ConfigDialog();
\ No newline at end of file
+export const configDialog = new ConfigDialog();
diff --git a/web/drizzle/0022_petite_bishop.sql b/web/drizzle/0022_petite_bishop.sql
new file mode 100644
index 0000000..b52e475
--- /dev/null
+++ b/web/drizzle/0022_petite_bishop.sql
@@ -0,0 +1 @@
+ALTER TABLE "comfyui_deploy"."workflow_versions" ADD COLUMN "snapshot" jsonb;
\ No newline at end of file
diff --git a/web/drizzle/meta/0022_snapshot.json b/web/drizzle/meta/0022_snapshot.json
new file mode 100644
index 0000000..e546133
--- /dev/null
+++ b/web/drizzle/meta/0022_snapshot.json
@@ -0,0 +1,710 @@
+{
+ "id": "9153404d-9279-4f43-a61f-7f5efefc12b7",
+ "prevId": "5893c5f8-4466-4b51-b9b7-24756c37dced",
+ "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
+ },
+ "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"
+ }
+ },
+ "machine_status": {
+ "name": "machine_status",
+ "values": {
+ "ready": "ready",
+ "building": "building",
+ "error": "error"
+ }
+ },
+ "machine_type": {
+ "name": "machine_type",
+ "values": {
+ "classic": "classic",
+ "runpod-serverless": "runpod-serverless",
+ "modal-serverless": "modal-serverless",
+ "comfy-deploy-serverless": "comfy-deploy-serverless"
+ }
+ },
+ "workflow_run_origin": {
+ "name": "workflow_run_origin",
+ "values": {
+ "manual": "manual",
+ "api": "api"
+ }
+ },
+ "workflow_run_status": {
+ "name": "workflow_run_status",
+ "values": {
+ "not-started": "not-started",
+ "running": "running",
+ "uploading": "uploading",
+ "success": "success",
+ "failed": "failed"
+ }
+ }
+ },
+ "schemas": {
+ "comfyui_deploy": "comfyui_deploy"
+ },
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ }
+}
\ No newline at end of file
diff --git a/web/drizzle/meta/_journal.json b/web/drizzle/meta/_journal.json
index 4faf384..c0a4c41 100644
--- a/web/drizzle/meta/_journal.json
+++ b/web/drizzle/meta/_journal.json
@@ -155,6 +155,13 @@
"when": 1704380757696,
"tag": "0021_aromatic_sabra",
"breakpoints": true
+ },
+ {
+ "idx": 22,
+ "version": "5",
+ "when": 1704453649633,
+ "tag": "0022_petite_bishop",
+ "breakpoints": true
}
]
}
\ No newline at end of file
diff --git a/web/src/app/(app)/api/upload/route.ts b/web/src/app/(app)/api/upload/route.ts
index 93fe167..c6c2d8f 100644
--- a/web/src/app/(app)/api/upload/route.ts
+++ b/web/src/app/(app)/api/upload/route.ts
@@ -1,6 +1,7 @@
import { parseJWT } from "../../../../server/parseJWT";
import { db } from "@/db/db";
import {
+ snapshotType,
workflowAPIType,
workflowTable,
workflowType,
@@ -18,11 +19,11 @@ const corsHeaders = {
};
const UploadRequest = z.object({
- // user_id: z.string(),
workflow_id: z.string().optional(),
- workflow_name: z.string().optional(),
+ workflow_name: z.string().min(1).optional(),
workflow: workflowType,
workflow_api: workflowAPIType,
+ snapshot: snapshotType,
});
export async function OPTIONS(request: Request) {
@@ -64,6 +65,7 @@ export async function POST(request: Request) {
workflow_api,
workflow_id: _workflow_id,
workflow_name,
+ snapshot,
} = data;
let workflow_id = _workflow_id;
@@ -93,6 +95,7 @@ export async function POST(request: Request) {
workflow,
workflow_api,
version: 1,
+ snapshot: snapshot,
})
.returning();
version = data[0].version;
@@ -105,6 +108,7 @@ export async function POST(request: Request) {
workflow: workflow,
workflow_api,
// version: sql`${workflowVersionTable.version} + 1`,
+ snapshot: snapshot,
version: sql`(
SELECT COALESCE(MAX(version), 0) + 1
FROM ${workflowVersionTable}
diff --git a/web/src/db/schema.ts b/web/src/db/schema.ts
index aa27b59..bb1c65d 100644
--- a/web/src/db/schema.ts
+++ b/web/src/db/schema.ts
@@ -69,6 +69,7 @@ export const workflowVersionTable = dbSchema.table("workflow_versions", {
workflow: jsonb("workflow").$type>(),
workflow_api: jsonb("workflow_api").$type>(),
version: integer("version").notNull(),
+ snapshot: jsonb("snapshot").$type>(),
created_at: timestamp("created_at").defaultNow().notNull(),
updated_at: timestamp("updated_at").defaultNow().notNull(),
@@ -201,10 +202,21 @@ export const machinesTable = dbSchema.table("machines", {
auth_token: text("auth_token"),
type: machinesType("type").notNull().default("classic"),
status: machinesStatus("status").notNull().default("ready"),
- snapshot: jsonb("snapshot").$type(),
+ snapshot: jsonb("snapshot").$type>(),
build_log: text("build_log"),
});
+export const snapshotType = z.object({
+ comfyui: z.string(),
+ git_custom_nodes: z.record(
+ z.object({
+ hash: z.string(),
+ disabled: z.boolean(),
+ })
+ ),
+ file_custom_nodes: z.array(z.any()),
+});
+
export const insertMachineSchema = createInsertSchema(machinesTable, {
name: (schema) => schema.name.default("My Machine"),
endpoint: (schema) => schema.endpoint.default("http://127.0.0.1:8188"),