diff --git a/web-plugin/index.js b/web-plugin/index.js
index 8b80364..3ab28ab 100644
--- a/web-plugin/index.js
+++ b/web-plugin/index.js
@@ -6,336 +6,433 @@ import { generateDependencyGraph } from "https://esm.sh/comfyui-json@0.1.25";
const loadingIcon = ``;
function sendEventToCD(event, data) {
- const message = {
- type: event,
- data: data,
- };
- window.parent.postMessage(JSON.stringify(message), "*");
+ const message = {
+ type: event,
+ data: data,
+ };
+ window.parent.postMessage(JSON.stringify(message), "*");
}
function dispatchAPIEventData(data) {
- const msg = JSON.parse(data);
+ const msg = JSON.parse(data);
- // Custom parse error
- if (msg.error) {
- let message = msg.error.message;
- if (msg.error.details) message += ": " + msg.error.details;
- for (const [nodeID, nodeError] of Object.entries(msg.node_errors)) {
- message += "\n" + nodeError.class_type + ":";
- for (const errorReason of nodeError.errors) {
- message +=
- "\n - " + errorReason.message + ": " + errorReason.details;
- }
+ // Custom parse error
+ if (msg.error) {
+ let message = msg.error.message;
+ if (msg.error.details) message += ": " + msg.error.details;
+ for (const [nodeID, nodeError] of Object.entries(msg.node_errors)) {
+ message += "\n" + nodeError.class_type + ":";
+ for (const errorReason of nodeError.errors) {
+ message +=
+ "\n - " +
+ errorReason.message +
+ ": " +
+ errorReason.details;
+ }
+ }
+
+ app.ui.dialog.show(message);
+ if (msg.node_errors) {
+ app.lastNodeErrors = msg.node_errors;
+ app.canvas.draw(true, true);
+ }
}
- app.ui.dialog.show(message);
- if (msg.node_errors) {
- app.lastNodeErrors = msg.node_errors;
- app.canvas.draw(true, true);
+ switch (msg.event) {
+ case "error":
+ break;
+ case "status":
+ if (msg.data.sid) {
+ // this.clientId = msg.data.sid;
+ // window.name = this.clientId; // use window name so it isnt reused when duplicating tabs
+ // sessionStorage.setItem("clientId", this.clientId); // store in session storage so duplicate tab can load correct workflow
+ }
+ api.dispatchEvent(
+ new CustomEvent("status", { detail: msg.data.status })
+ );
+ break;
+ case "progress":
+ api.dispatchEvent(
+ new CustomEvent("progress", { detail: msg.data })
+ );
+ break;
+ case "executing":
+ api.dispatchEvent(
+ new CustomEvent("executing", { detail: msg.data.node })
+ );
+ break;
+ case "executed":
+ api.dispatchEvent(
+ new CustomEvent("executed", { detail: msg.data })
+ );
+ break;
+ case "execution_start":
+ api.dispatchEvent(
+ new CustomEvent("execution_start", { detail: msg.data })
+ );
+ break;
+ case "execution_error":
+ api.dispatchEvent(
+ new CustomEvent("execution_error", { detail: msg.data })
+ );
+ break;
+ case "execution_cached":
+ api.dispatchEvent(
+ new CustomEvent("execution_cached", { detail: msg.data })
+ );
+ break;
+ default:
+ api.dispatchEvent(new CustomEvent(msg.type, { detail: msg.data }));
+ // default:
+ // if (this.#registered.has(msg.type)) {
+ // } else {
+ // throw new Error(`Unknown message type ${msg.type}`);
+ // }
}
- }
-
- switch (msg.event) {
- case "error":
- break;
- case "status":
- if (msg.data.sid) {
- // this.clientId = msg.data.sid;
- // window.name = this.clientId; // use window name so it isnt reused when duplicating tabs
- // sessionStorage.setItem("clientId", this.clientId); // store in session storage so duplicate tab can load correct workflow
- }
- api.dispatchEvent(new CustomEvent("status", { detail: msg.data.status }));
- break;
- case "progress":
- api.dispatchEvent(new CustomEvent("progress", { detail: msg.data }));
- break;
- case "executing":
- api.dispatchEvent(
- new CustomEvent("executing", { detail: msg.data.node }),
- );
- break;
- case "executed":
- api.dispatchEvent(new CustomEvent("executed", { detail: msg.data }));
- break;
- case "execution_start":
- api.dispatchEvent(
- new CustomEvent("execution_start", { detail: msg.data }),
- );
- break;
- case "execution_error":
- api.dispatchEvent(
- new CustomEvent("execution_error", { detail: msg.data }),
- );
- break;
- case "execution_cached":
- api.dispatchEvent(
- new CustomEvent("execution_cached", { detail: msg.data }),
- );
- break;
- default:
- api.dispatchEvent(new CustomEvent(msg.type, { detail: msg.data }));
- // default:
- // if (this.#registered.has(msg.type)) {
- // } else {
- // throw new Error(`Unknown message type ${msg.type}`);
- // }
- }
}
/** @typedef {import('../../../web/types/comfy.js').ComfyExtension} ComfyExtension*/
/** @type {ComfyExtension} */
const ext = {
- name: "BennyKok.ComfyUIDeploy",
+ name: "BennyKok.ComfyUIDeploy",
- init(app) {
- addButton();
+ init(app) {
+ addButton();
- const queryParams = new URLSearchParams(window.location.search);
- const workflow_version_id = queryParams.get("workflow_version_id");
- const auth_token = queryParams.get("auth_token");
- const org_display = queryParams.get("org_display");
- const origin = queryParams.get("origin");
- const workspace_mode = queryParams.get("workspace_mode");
+ const queryParams = new URLSearchParams(window.location.search);
+ const workflow_version_id = queryParams.get("workflow_version_id");
+ const auth_token = queryParams.get("auth_token");
+ const org_display = queryParams.get("org_display");
+ const origin = queryParams.get("origin");
+ const workspace_mode = queryParams.get("workspace_mode");
- if (workspace_mode) {
- document.querySelector(".comfy-menu").style.display = "none";
+ if (workspace_mode) {
+ document.querySelector(".comfy-menu").style.display = "none";
- sendEventToCD("cd_plugin_onInit");
+ sendEventToCD("cd_plugin_onInit");
- app.queuePrompt = ((originalFunction) => async () => {
- // const prompt = await app.graphToPrompt();
- sendEventToCD("cd_plugin_onQueuePromptTrigger");
- })(app.queuePrompt);
+ app.queuePrompt = ((originalFunction) => async () => {
+ // const prompt = await app.graphToPrompt();
+ sendEventToCD("cd_plugin_onQueuePromptTrigger");
+ })(app.queuePrompt);
- // // Intercept the onkeydown event
- // window.addEventListener(
- // "keydown",
- // (event) => {
- // // Check for specific keys if necessary
- // console.log("hi");
- // if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
- // event.preventDefault();
- // event.stopImmediatePropagation();
- // event.stopPropagation();
- // sendEventToCD("cd_plugin_onQueuePrompt", prompt);
- // }
- // },
- // true,
- // );
- }
+ // // Intercept the onkeydown event
+ // window.addEventListener(
+ // "keydown",
+ // (event) => {
+ // // Check for specific keys if necessary
+ // console.log("hi");
+ // if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
+ // event.preventDefault();
+ // event.stopImmediatePropagation();
+ // event.stopPropagation();
+ // sendEventToCD("cd_plugin_onQueuePrompt", prompt);
+ // }
+ // },
+ // true,
+ // );
+ }
- const data = getData();
- let endpoint = data.endpoint;
- let apiKey = data.apiKey;
+ const data = getData();
+ let endpoint = data.endpoint;
+ let apiKey = data.apiKey;
- // If there is auth token override it
- if (auth_token) {
- apiKey = auth_token;
- endpoint = origin;
- saveData({
- displayName: org_display,
- endpoint: origin,
- apiKey: auth_token,
- displayName: org_display,
- environment: "cloud",
- });
- localStorage.setItem("comfy_deploy_env", "cloud");
- }
+ // If there is auth token override it
+ if (auth_token) {
+ apiKey = auth_token;
+ endpoint = origin;
+ saveData({
+ displayName: org_display,
+ endpoint: origin,
+ apiKey: auth_token,
+ displayName: org_display,
+ environment: "cloud",
+ });
+ localStorage.setItem("comfy_deploy_env", "cloud");
+ }
- if (!workflow_version_id) {
- console.error("No workflow_version_id provided in query parameters.");
- } else {
- loadingDialog.showLoading(
- "Loading workflow from " + org_display,
- "Please wait...",
- );
- fetch(endpoint + "/api/workflow-version/" + workflow_version_id, {
- method: "GET",
- headers: {
- "Content-Type": "application/json",
- Authorization: "Bearer " + apiKey,
- },
- })
- .then(async (res) => {
- const data = await res.json();
- const { workflow, workflow_id, error } = data;
- if (error) {
- infoDialog.showMessage("Unable to load this workflow", error);
- return;
- }
+ if (!workflow_version_id) {
+ console.error(
+ "No workflow_version_id provided in query parameters."
+ );
+ } else {
+ loadingDialog.showLoading(
+ "Loading workflow from " + org_display,
+ "Please wait..."
+ );
+ fetch(endpoint + "/api/workflow-version/" + workflow_version_id, {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: "Bearer " + apiKey,
+ },
+ })
+ .then(async (res) => {
+ const data = await res.json();
+ const { workflow, workflow_id, error } = data;
+ if (error) {
+ infoDialog.showMessage(
+ "Unable to load this workflow",
+ error
+ );
+ return;
+ }
- // // Adding a delay to wait for the intial graph to load
- // await new Promise((resolve) => setTimeout(resolve, 2000));
+ // // Adding a delay to wait for the intial graph to load
+ // await new Promise((resolve) => setTimeout(resolve, 2000));
- workflow?.nodes.forEach((x) => {
- if (x?.type === "ComfyDeploy") {
- x.widgets_values[1] = workflow_id;
- // x.widgets_values[2] = workflow_version.version;
+ workflow?.nodes.forEach((x) => {
+ if (x?.type === "ComfyDeploy") {
+ x.widgets_values[1] = workflow_id;
+ // x.widgets_values[2] = workflow_version.version;
+ }
+ });
+
+ /** @type {LGraph} */
+ app.loadGraphData(workflow);
+ })
+ .catch((e) => infoDialog.showMessage("Error", e.message))
+ .finally(() => {
+ loadingDialog.close();
+ window.history.replaceState(
+ {},
+ document.title,
+ window.location.pathname
+ );
+ });
+ }
+ },
+
+ registerCustomNodes() {
+ /** @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 = "";
+ this.properties.version = "";
+ }
+
+ 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
+ );
+
+ ComfyWidgets.STRING(
+ this,
+ "version",
+ [
+ "",
+ { default: this.properties.version, 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;
}
- });
+ }
- /** @type {LGraph} */
- app.loadGraphData(workflow);
- })
- .catch((e) => infoDialog.showMessage("Error", e.message))
- .finally(() => {
- loadingDialog.close();
- window.history.replaceState(
- {},
- document.title,
- window.location.pathname,
- );
+ // Load default visibility
+
+ LiteGraph.registerNodeType(
+ "ComfyDeploy",
+ 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", async (event) => {
+ // console.log("message", event);
+ try {
+ const message = JSON.parse(event.data);
+ if (message.type === "graph_load") {
+ const comfyUIWorkflow = message.data;
+ // console.log("recieved: ", comfyUIWorkflow);
+ // Assuming there's a method to load the workflow data into the ComfyUI
+ // This part of the code would depend on how the ComfyUI expects to receive and process the workflow data
+ // For demonstration, let's assume there's a loadWorkflow method in the ComfyUI API
+ if (comfyUIWorkflow && app && app.loadGraphData) {
+ console.log("loadGraphData");
+ app.loadGraphData(comfyUIWorkflow);
+ }
+ } else if (message.type === "deploy") {
+ // deployWorkflow();
+ const prompt = await app.graphToPrompt();
+ // api.handlePromptGenerated(prompt);
+ sendEventToCD("cd_plugin_onDeployChanges", prompt);
+ } else if (message.type === "queue_prompt") {
+ const prompt = await app.graphToPrompt();
+ if (typeof api.handlePromptGenerated === "function") {
+ api.handlePromptGenerated(prompt);
+ } else {
+ console.warn(
+ "api.handlePromptGenerated is not a function"
+ );
+ }
+ sendEventToCD("cd_plugin_onQueuePrompt", prompt);
+ } else if (message.type === "get_prompt") {
+ const prompt = await app.graphToPrompt();
+ sendEventToCD("cd_plugin_onGetPrompt", prompt);
+ } else if (message.type === "event") {
+ dispatchAPIEventData(message.data);
+ } else if (message.type === "add_node") {
+ console.log("add node", message.data);
+ app.graph.beforeChange();
+ var node = LiteGraph.createNode(message.data.type);
+ node.configure({
+ widgets_values: message.data.widgets_values,
+ });
+
+ console.log("node", node);
+
+ const graphMouse = app.canvas.graph_mouse;
+
+ node.pos = [graphMouse[0], graphMouse[1]];
+
+ app.graph.add(node);
+ app.graph.afterChange();
+ } else if (message.type === "zoom_to_node") {
+ const nodeId = message.data.nodeId;
+ const position = message.data.position;
+
+ const node = app.graph.getNodeById(nodeId);
+ if (!node) return;
+
+ const canvas = app.canvas;
+ const targetScale = 1;
+ const targetOffsetX =
+ canvas.canvas.width / 4 -
+ position[0] -
+ node.size[0] / 2;
+ const targetOffsetY =
+ canvas.canvas.height / 4 -
+ position[1] -
+ node.size[1] / 2;
+
+ const startScale = canvas.ds.scale;
+ const startOffsetX = canvas.ds.offset[0];
+ const startOffsetY = canvas.ds.offset[1];
+
+ const duration = 400; // Animation duration in milliseconds
+ const startTime = Date.now();
+
+ function easeOutCubic(t) {
+ return 1 - Math.pow(1 - t, 3);
+ }
+
+ function lerp(start, end, t) {
+ return start * (1 - t) + end * t;
+ }
+
+ function animate() {
+ const currentTime = Date.now();
+ const elapsedTime = currentTime - startTime;
+ const t = Math.min(elapsedTime / duration, 1);
+
+ const easedT = easeOutCubic(t);
+
+ const currentScale = lerp(
+ startScale,
+ targetScale,
+ easedT
+ );
+ const currentOffsetX = lerp(
+ startOffsetX,
+ targetOffsetX,
+ easedT
+ );
+ const currentOffsetY = lerp(
+ startOffsetY,
+ targetOffsetY,
+ easedT
+ );
+
+ canvas.setZoom(currentScale);
+ canvas.ds.offset = [currentOffsetX, currentOffsetY];
+ canvas.draw(true, true);
+
+ if (t < 1) {
+ requestAnimationFrame(animate);
+ }
+ }
+
+ animate();
+ }
+ // else if (message.type === "refresh") {
+ // sendEventToCD("cd_plugin_onRefresh");
+ // }
+ } catch (error) {
+ // console.error("Error processing message:", error);
+ }
});
- }
- },
- 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 = "";
- this.properties.version = "";
- }
+ 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) {
- 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,
- );
+ app.graph.onAfterChange = ((originalFunction) =>
+ async function () {
+ const prompt = await app.graphToPrompt();
+ sendEventToCD("cd_plugin_onAfterChange", prompt);
- ComfyWidgets.STRING(
- this,
- "version",
- ["", { default: this.properties.version, multiline: false }],
- app,
- );
+ if (typeof originalFunction === "function") {
+ originalFunction.apply(this, arguments);
+ }
+ })(app.graph.onAfterChange);
- // 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(
- "ComfyDeploy",
- 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", async (event) => {
- // console.log("message", event);
- try {
- const message = JSON.parse(event.data);
- if (message.type === "graph_load") {
- const comfyUIWorkflow = message.data;
- // console.log("recieved: ", comfyUIWorkflow);
- // Assuming there's a method to load the workflow data into the ComfyUI
- // This part of the code would depend on how the ComfyUI expects to receive and process the workflow data
- // For demonstration, let's assume there's a loadWorkflow method in the ComfyUI API
- if (comfyUIWorkflow && app && app.loadGraphData) {
- console.log("loadGraphData");
- app.loadGraphData(comfyUIWorkflow);
- }
- } else if (message.type === "deploy") {
- // deployWorkflow();
- const prompt = await app.graphToPrompt();
- // api.handlePromptGenerated(prompt);
- sendEventToCD("cd_plugin_onDeployChanges", prompt);
- } else if (message.type === "queue_prompt") {
- const prompt = await app.graphToPrompt();
- if (typeof api.handlePromptGenerated === "function") {
- api.handlePromptGenerated(prompt);
- } else {
- console.warn("api.handlePromptGenerated is not a function");
- }
- sendEventToCD("cd_plugin_onQueuePrompt", prompt);
- } else if (message.type === "get_prompt") {
- const prompt = await app.graphToPrompt();
- sendEventToCD("cd_plugin_onGetPrompt", prompt);
- } else if (message.type === "event") {
- dispatchAPIEventData(message.data);
- } else if (message.type === "add_node") {
- console.log("add node", message.data);
- app.graph.beforeChange();
- var node = LiteGraph.createNode(message.data.type);
- node.configure({
- widgets_values: message.data.widgets_values,
- });
-
- console.log("node", node);
-
- const graphMouse = app.canvas.graph_mouse;
-
- node.pos = [graphMouse[0], graphMouse[1]];
-
- app.graph.add(node);
- app.graph.afterChange();
- }
- // else if (message.type === "refresh") {
- // sendEventToCD("cd_plugin_onRefresh");
- // }
- } catch (error) {
- // console.error("Error processing message:", error);
- }
- });
-
- 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) {
-
- // }
- });
-
- app.graph.onAfterChange = ((originalFunction) =>
- async function () {
- const prompt = await app.graphToPrompt();
- sendEventToCD("cd_plugin_onAfterChange", prompt);
-
- if (typeof originalFunction === "function") {
- originalFunction.apply(this, arguments);
- }
- })(app.graph.onAfterChange);
-
- sendEventToCD("cd_plugin_setup");
- },
+ sendEventToCD("cd_plugin_setup");
+ },
};
/**
@@ -344,133 +441,138 @@ const ext = {
*/
function showError(title, message) {
- infoDialog.show(
- `
';
- const bgcolor = "var(--comfy-input-bg)";
- const evenBg = "var(--border-color)";
- const textColor = "var(--input-text)";
+ console.log(data);
+ let html =
+ '
';
+ const bgcolor = "var(--comfy-input-bg)";
+ const evenBg = "var(--border-color)";
+ const textColor = "var(--input-text)";
- // Custom Nodes
- html += `
`;
- html +=
- '
Custom Nodes
';
+ // Custom Nodes
+ html += `
`;
+ html +=
+ '
Custom Nodes
';
- if (data.missing_nodes?.length > 0) {
- html += `
+ if (data.missing_nodes?.length > 0) {
+ html += `
Missing Nodes
These nodes are not found with any matching custom_nodes in the ComfyUI Manager Database
${data.missing_nodes
- .map((node) => {
- return `
${node}
`;
- })
- .join("")}
+ .map((node) => {
+ return `
${node}
`;
+ })
+ .join("")}
`;
- }
+ }
- Object.values(data.custom_nodes).forEach((node) => {
- html += `
+ Object.values(data.custom_nodes).forEach((node) => {
+ html += `
`;
- });
- html += "
";
-
- // Models
- html += `
`;
- html +=
- '
Models
';
-
- Object.entries(data.models).forEach(([section, items]) => {
- html += `
-
-
${section.charAt(0).toUpperCase() + section.slice(1)
- }
`;
- items.forEach((item) => {
- html += `
${item.name}
`;
});
html += "
";
- });
- html += "
";
- // Models
- html += `
`;
- html +=
- '
Files
';
+ // Models
+ html += `
`;
+ html +=
+ '
Models
';
- Object.entries(data.files).forEach(([section, items]) => {
- html += `
+ Object.entries(data.models).forEach(([section, items]) => {
+ html += `
-
${section.charAt(0).toUpperCase() + section.slice(1)
- }
`;
- items.forEach((item) => {
- html += `
${item.name}
`;
+
${
+ section.charAt(0).toUpperCase() + section.slice(1)
+ }
`;
+ items.forEach((item) => {
+ html += `
${item.name}
`;
+ });
+ html += "
";
});
html += "
";
- });
- html += "
";
- html += "
";
- return html;
+ // Models
+ html += `
`;
+ html +=
+ '
Files
';
+
+ Object.entries(data.files).forEach(([section, items]) => {
+ html += `
+
+
${
+ section.charAt(0).toUpperCase() + section.slice(1)
+ }
`;
+ items.forEach((item) => {
+ html += `
${item.name}
`;
+ });
+ html += "
";
+ });
+ html += "
";
+
+ html += "
";
+ return html;
}
async function deployWorkflow() {
- const deploy = document.getElementById("deploy-button");
+ const deploy = document.getElementById("deploy-button");
- /** @type {LGraph} */
- const graph = app.graph;
+ /** @type {LGraph} */
+ const graph = app.graph;
- let { endpoint, apiKey, displayName } = getData();
+ let { endpoint, apiKey, displayName } = getData();
- if (!endpoint || !apiKey || apiKey === "" || endpoint === "") {
- configDialog.show();
- return;
- }
+ if (!endpoint || !apiKey || apiKey === "" || endpoint === "") {
+ configDialog.show();
+ return;
+ }
- let deployMeta = graph.findNodesByType("ComfyDeploy");
+ 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];
- }
+ 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];
+ }
- const deployMetaNode = deployMeta[0];
+ const deployMetaNode = deployMeta[0];
- const workflow_name = deployMetaNode.widgets[0].value;
- const workflow_id = deployMetaNode.widgets[1].value;
+ const workflow_name = deployMetaNode.widgets[0].value;
+ const workflow_id = deployMetaNode.widgets[1].value;
- const ok = await confirmDialog.confirm(
- `Confirm deployment`,
- `
+ const ok = await confirmDialog.confirm(
+ `Confirm deployment`,
+ `
A new version of will be deployed, do you confirm?
@@ -489,261 +591,269 @@ async function deployWorkflow() {
Reuse hash from last version
- `,
- );
- if (!ok) return;
-
- const includeDeps = document.getElementById("include-deps").checked;
- const reuseHash = document.getElementById("reuse-hash").checked;
-
- if (endpoint.endsWith("/")) {
- endpoint = endpoint.slice(0, -1);
- }
- loadingDialog.showLoading("Generating snapshot");
-
- const snapshot = await fetch("/snapshot/get_current").then((x) => x.json());
- // console.log(snapshot);
- loadingDialog.close();
-
- if (!snapshot) {
- showError(
- "Error when deploying",
- "Unable to generate snapshot, please install ComfyUI Manager",
+ `
);
- return;
- }
+ if (!ok) return;
- const title = deploy.querySelector("#button-title");
+ const includeDeps = document.getElementById("include-deps").checked;
+ const reuseHash = document.getElementById("reuse-hash").checked;
- const prompt = await app.graphToPrompt();
- let deps = undefined;
-
- if (includeDeps) {
- loadingDialog.showLoading("Fetching existing version");
-
- const existing_workflow = await fetch(
- endpoint + "/api/workflow/" + workflow_id,
- {
- method: "GET",
- headers: {
- "Content-Type": "application/json",
- Authorization: "Bearer " + apiKey,
- },
- },
- )
- .then((x) => x.json())
- .catch(() => {
- return {};
- });
+ if (endpoint.endsWith("/")) {
+ endpoint = endpoint.slice(0, -1);
+ }
+ loadingDialog.showLoading("Generating snapshot");
+ const snapshot = await fetch("/snapshot/get_current").then((x) => x.json());
+ // console.log(snapshot);
loadingDialog.close();
- loadingDialog.showLoading("Generating dependency graph");
- deps = await generateDependencyGraph({
- workflow_api: prompt.output,
- snapshot: snapshot,
- computeFileHash: async (file) => {
- console.log(existing_workflow?.dependencies?.models);
+ if (!snapshot) {
+ showError(
+ "Error when deploying",
+ "Unable to generate snapshot, please install ComfyUI Manager"
+ );
+ return;
+ }
- // Match previous hash for models
- if (reuseHash && existing_workflow?.dependencies?.models) {
- const previousModelHash = Object.entries(
- existing_workflow?.dependencies?.models,
- ).flatMap(([key, value]) => {
- return Object.values(value).map((x) => ({
- ...x,
- name: "models/" + key + "/" + x.name,
- }));
- });
- console.log(previousModelHash);
+ const title = deploy.querySelector("#button-title");
- const match = previousModelHash.find((x) => {
- console.log(file, x.name);
- return file == x.name;
- });
- console.log(match);
- if (match && match.hash) {
- console.log("cached hash used");
- return match.hash;
- }
- }
- console.log(file);
- loadingDialog.showLoading("Generating hash", file);
- const hash = await fetch(
- `/comfyui-deploy/get-file-hash?file_path=${encodeURIComponent(file)}`,
- ).then((x) => x.json());
- loadingDialog.showLoading("Generating hash", file);
- console.log(hash);
- return hash.file_hash;
- },
- handleFileUpload: async (file, hash, prevhash) => {
- console.log("Uploading ", file);
- loadingDialog.showLoading("Uploading file", file);
- try {
- const { download_url } = await fetch(`/comfyui-deploy/upload-file`, {
- method: "POST",
- body: JSON.stringify({
- file_path: file,
- token: apiKey,
- url: endpoint + "/api/upload-url",
- }),
- })
+ const prompt = await app.graphToPrompt();
+ let deps = undefined;
+
+ if (includeDeps) {
+ loadingDialog.showLoading("Fetching existing version");
+
+ const existing_workflow = await fetch(
+ endpoint + "/api/workflow/" + workflow_id,
+ {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: "Bearer " + apiKey,
+ },
+ }
+ )
.then((x) => x.json())
.catch(() => {
- loadingDialog.close();
- confirmDialog.confirm("Error", "Unable to upload file " + file);
+ return {};
});
- loadingDialog.showLoading("Uploaded file", file);
- console.log(download_url);
- return download_url;
- } catch (error) {
- return undefined;
- }
- },
- existingDependencies: existing_workflow.dependencies,
- });
- // Need to find a way to include this if this is not included in comfyui-json level
- if (
- !deps.custom_nodes["https://github.com/BennyKok/comfyui-deploy"] &&
- !deps.custom_nodes["https://github.com/BennyKok/comfyui-deploy.git"]
- )
- deps.custom_nodes["https://github.com/BennyKok/comfyui-deploy"] = {
- url: "https://github.com/BennyKok/comfyui-deploy",
- install_type: "git-clone",
- hash:
- snapshot?.git_custom_nodes?.[
- "https://github.com/BennyKok/comfyui-deploy"
- ]?.hash ?? "HEAD",
- name: "ComfyUI Deploy",
- };
+ loadingDialog.close();
- loadingDialog.close();
+ loadingDialog.showLoading("Generating dependency graph");
+ deps = await generateDependencyGraph({
+ workflow_api: prompt.output,
+ snapshot: snapshot,
+ computeFileHash: async (file) => {
+ console.log(existing_workflow?.dependencies?.models);
- const depsOk = await confirmDialog.confirm(
- "Check dependencies",
- // JSON.stringify(deps, null, 2),
- `
+ // Match previous hash for models
+ if (reuseHash && existing_workflow?.dependencies?.models) {
+ const previousModelHash = Object.entries(
+ existing_workflow?.dependencies?.models
+ ).flatMap(([key, value]) => {
+ return Object.values(value).map((x) => ({
+ ...x,
+ name: "models/" + key + "/" + x.name,
+ }));
+ });
+ console.log(previousModelHash);
+
+ const match = previousModelHash.find((x) => {
+ console.log(file, x.name);
+ return file == x.name;
+ });
+ console.log(match);
+ if (match && match.hash) {
+ console.log("cached hash used");
+ return match.hash;
+ }
+ }
+ console.log(file);
+ loadingDialog.showLoading("Generating hash", file);
+ const hash = await fetch(
+ `/comfyui-deploy/get-file-hash?file_path=${encodeURIComponent(
+ file
+ )}`
+ ).then((x) => x.json());
+ loadingDialog.showLoading("Generating hash", file);
+ console.log(hash);
+ return hash.file_hash;
+ },
+ handleFileUpload: async (file, hash, prevhash) => {
+ console.log("Uploading ", file);
+ loadingDialog.showLoading("Uploading file", file);
+ try {
+ const { download_url } = await fetch(
+ `/comfyui-deploy/upload-file`,
+ {
+ method: "POST",
+ body: JSON.stringify({
+ file_path: file,
+ token: apiKey,
+ url: endpoint + "/api/upload-url",
+ }),
+ }
+ )
+ .then((x) => x.json())
+ .catch(() => {
+ loadingDialog.close();
+ confirmDialog.confirm(
+ "Error",
+ "Unable to upload file " + file
+ );
+ });
+ loadingDialog.showLoading("Uploaded file", file);
+ console.log(download_url);
+ return download_url;
+ } catch (error) {
+ return undefined;
+ }
+ },
+ existingDependencies: existing_workflow.dependencies,
+ });
+
+ // Need to find a way to include this if this is not included in comfyui-json level
+ if (
+ !deps.custom_nodes["https://github.com/BennyKok/comfyui-deploy"] &&
+ !deps.custom_nodes["https://github.com/BennyKok/comfyui-deploy.git"]
+ )
+ deps.custom_nodes["https://github.com/BennyKok/comfyui-deploy"] = {
+ url: "https://github.com/BennyKok/comfyui-deploy",
+ install_type: "git-clone",
+ hash:
+ snapshot?.git_custom_nodes?.[
+ "https://github.com/BennyKok/comfyui-deploy"
+ ]?.hash ?? "HEAD",
+ name: "ComfyUI Deploy",
+ };
+
+ loadingDialog.close();
+
+ const depsOk = await confirmDialog.confirm(
+ "Check dependencies",
+ // JSON.stringify(deps, null, 2),
+ `
${loadingIcon}
`,
- // createDynamicUIHtml(deps),
- );
- if (!depsOk) return;
+ JSON.stringify(deps)
+ )}" />`
+ // createDynamicUIHtml(deps),
+ );
+ if (!depsOk) return;
- console.log(deps);
- }
-
- loadingDialog.showLoading("Deploying...");
-
- title.innerText = "Deploying...";
- title.style.color = "orange";
-
- // console.log(prompt);
-
- // TODO trim the ending / from endpoint is there is
- if (endpoint.endsWith("/")) {
- endpoint = endpoint.slice(0, -1);
- }
-
- // console.log(prompt.workflow);
-
- const apiRoute = endpoint + "/api/workflow";
- // const userId = apiKey
- try {
- const body = {
- workflow_name,
- workflow_id,
- workflow: prompt.workflow,
- workflow_api: prompt.output,
- snapshot: snapshot,
- dependencies: deps,
- };
- console.log(body);
- let data = await fetch(apiRoute, {
- method: "POST",
- body: JSON.stringify(body),
- headers: {
- "Content-Type": "application/json",
- Authorization: "Bearer " + apiKey,
- },
- });
-
- console.log(data);
-
- if (data.status !== 200) {
- throw new Error(await data.text());
- } else {
- data = await data.json();
+ console.log(deps);
}
- loadingDialog.close();
+ loadingDialog.showLoading("Deploying...");
- title.textContent = "Done";
- title.style.color = "green";
+ title.innerText = "Deploying...";
+ title.style.color = "orange";
- deployMetaNode.widgets[1].value = data.workflow_id;
- deployMetaNode.widgets[2].value = data.version;
- graph.change();
+ // console.log(prompt);
- infoDialog.show(
- `
Deployed successfully! -> View here Workflow ID: ${data.workflow_id}
Workflow Name: ${workflow_name}
Workflow Version: ${data.version}
`,
- );
+ // TODO trim the ending / from endpoint is there is
+ if (endpoint.endsWith("/")) {
+ endpoint = endpoint.slice(0, -1);
+ }
- setTimeout(() => {
- title.textContent = "Deploy";
- title.style.color = "white";
- }, 1000);
- } catch (e) {
- loadingDialog.close();
- app.ui.dialog.show(e);
- console.error(e);
- title.textContent = "Error";
- title.style.color = "red";
- setTimeout(() => {
- title.textContent = "Deploy";
- title.style.color = "white";
- }, 1000);
- }
+ // console.log(prompt.workflow);
+
+ const apiRoute = endpoint + "/api/workflow";
+ // const userId = apiKey
+ try {
+ const body = {
+ workflow_name,
+ workflow_id,
+ workflow: prompt.workflow,
+ workflow_api: prompt.output,
+ snapshot: snapshot,
+ dependencies: deps,
+ };
+ console.log(body);
+ let data = await fetch(apiRoute, {
+ method: "POST",
+ body: JSON.stringify(body),
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: "Bearer " + apiKey,
+ },
+ });
+
+ console.log(data);
+
+ if (data.status !== 200) {
+ throw new Error(await data.text());
+ } else {
+ data = await data.json();
+ }
+
+ loadingDialog.close();
+
+ title.textContent = "Done";
+ title.style.color = "green";
+
+ deployMetaNode.widgets[1].value = data.workflow_id;
+ deployMetaNode.widgets[2].value = data.version;
+ graph.change();
+
+ infoDialog.show(
+ `
Deployed successfully! -> View here Workflow ID: ${data.workflow_id}
Workflow Name: ${workflow_name}
Workflow Version: ${data.version}
`
+ );
+
+ setTimeout(() => {
+ title.textContent = "Deploy";
+ title.style.color = "white";
+ }, 1000);
+ } catch (e) {
+ loadingDialog.close();
+ app.ui.dialog.show(e);
+ console.error(e);
+ title.textContent = "Error";
+ title.style.color = "red";
+ setTimeout(() => {
+ title.textContent = "Deploy";
+ title.style.color = "white";
+ }, 1000);
+ }
}
function addButton() {
- const menu = document.querySelector(".comfy-menu");
+ const menu = document.querySelector(".comfy-menu");
- const deploy = document.createElement("button");
- deploy.id = "deploy-button";
- deploy.style.position = "relative";
- deploy.style.display = "block";
- deploy.innerHTML = "
Deploy
";
- deploy.onclick = async () => {
- await deployWorkflow();
- };
+ const deploy = document.createElement("button");
+ deploy.id = "deploy-button";
+ deploy.style.position = "relative";
+ deploy.style.display = "block";
+ deploy.innerHTML = "
Deploy
";
+ deploy.onclick = async () => {
+ await deployWorkflow();
+ };
- const config = document.createElement("img");
- // config.style.padding = "0px 10px";
- config.style.height = "100%";
- config.style.position = "absolute";
- config.style.right = "10px";
- config.style.top = "0px";
+ const config = document.createElement("img");
+ // config.style.padding = "0px 10px";
+ config.style.height = "100%";
+ 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.onclick = (e) => {
- e.preventDefault();
- e.stopPropagation();
- configDialog.show();
- };
+ // set aspect ratio to square
+ config.style.width = "20px";
+ config.src =
+ "https://api.iconify.design/material-symbols-light:settings.svg?color=%23888888";
+ config.onclick = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ configDialog.show();
+ };
- deploy.append(config);
+ deploy.append(config);
- deploy.style.order = "99";
+ deploy.style.order = "99";
- menu.append(deploy);
+ menu.append(deploy);
}
app.registerExtension(ext);
@@ -751,42 +861,42 @@ app.registerExtension(ext);
import { ComfyDialog, $el } from "../../scripts/ui.js";
export class InfoDialog extends ComfyDialog {
- constructor() {
- super();
- this.element.classList.add("comfy-normal-modal");
- this.element.style.paddingBottom = "20px";
- }
-
- button = undefined;
-
- createButtons() {
- this.button = $el("button", {
- type: "button",
- textContent: "Close",
- onclick: () => this.close(),
- });
- return [this.button];
- }
-
- close() {
- this.element.style.display = "none";
- }
-
- show(html) {
- this.textElement.style["white-space"] = "normal";
- this.textElement.style.color = "white";
- this.textElement.style.marginTop = "0px";
- if (typeof html === "string") {
- this.textElement.innerHTML = html;
- } else {
- this.textElement.replaceChildren(html);
+ constructor() {
+ super();
+ this.element.classList.add("comfy-normal-modal");
+ this.element.style.paddingBottom = "20px";
}
- this.element.style.display = "flex";
- this.element.style.zIndex = 1001;
- }
- showMessage(title, message) {
- this.show(`
+ button = undefined;
+
+ createButtons() {
+ this.button = $el("button", {
+ type: "button",
+ textContent: "Close",
+ onclick: () => this.close(),
+ });
+ return [this.button];
+ }
+
+ close() {
+ this.element.style.display = "none";
+ }
+
+ show(html) {
+ this.textElement.style["white-space"] = "normal";
+ this.textElement.style.color = "white";
+ this.textElement.style.marginTop = "0px";
+ if (typeof html === "string") {
+ this.textElement.innerHTML = html;
+ } else {
+ this.textElement.replaceChildren(html);
+ }
+ this.element.style.display = "flex";
+ this.element.style.zIndex = 1001;
+ }
+
+ showMessage(title, message) {
+ this.show(`
${title}
`);
- }
+ }
- showLoading(title, message) {
- this.show(`
+ showLoading(title, message) {
+ this.show(`
${title} ${loadingIcon}
`);
- }
+ }
}
export class LoadingDialog extends ComfyDialog {
- constructor() {
- super();
- this.element.classList.add("comfy-normal-modal");
- // this.element.style.paddingBottom = "20px";
- }
-
- createButtons() {
- return [];
- }
-
- close() {
- this.element.style.display = "none";
- }
-
- show(html) {
- this.textElement.style["white-space"] = "normal";
- this.textElement.style.color = "white";
- this.textElement.style.marginTop = "0px";
- if (typeof html === "string") {
- this.textElement.innerHTML = html;
- } else {
- this.textElement.replaceChildren(html);
+ constructor() {
+ super();
+ this.element.classList.add("comfy-normal-modal");
+ // this.element.style.paddingBottom = "20px";
}
- this.element.style.display = "flex";
- this.element.style.zIndex = 1001;
- }
- loadingIcon = `
`;
+ createButtons() {
+ return [];
+ }
- showLoading(title, message) {
- this.show(`
+ close() {
+ this.element.style.display = "none";
+ }
+
+ show(html) {
+ this.textElement.style["white-space"] = "normal";
+ this.textElement.style.color = "white";
+ this.textElement.style.marginTop = "0px";
+ if (typeof html === "string") {
+ this.textElement.innerHTML = html;
+ } else {
+ this.textElement.replaceChildren(html);
+ }
+ this.element.style.display = "flex";
+ this.element.style.zIndex = 1001;
+ }
+
+ loadingIcon = `
`;
+
+ showLoading(title, message) {
+ this.show(`
-
${title} ${this.loadingIcon
- }
- ${message
- ? ``
- : ""
- }
+ ${title} ${
+ this.loadingIcon
+ }
+ ${
+ message
+ ? ``
+ : ""
+ }
`);
- }
+ }
}
export class InputDialog extends InfoDialog {
- callback = undefined;
+ callback = undefined;
- constructor() {
- super();
- }
+ constructor() {
+ super();
+ }
- createButtons() {
- return [
- $el(
- "div",
- {
- type: "div",
- style: {
- display: "flex",
- gap: "6px",
- justifyContent: "flex-end",
- width: "100%",
- },
- },
- [
- $el("button", {
- type: "button",
- textContent: "Close",
- onclick: () => {
- this.callback?.(undefined);
- this.close();
- },
- }),
- $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 = "";
- }
- },
- }),
- ],
- ),
- ];
- }
+ createButtons() {
+ return [
+ $el(
+ "div",
+ {
+ type: "div",
+ style: {
+ display: "flex",
+ gap: "6px",
+ justifyContent: "flex-end",
+ width: "100%",
+ },
+ },
+ [
+ $el("button", {
+ type: "button",
+ textContent: "Close",
+ onclick: () => {
+ this.callback?.(undefined);
+ this.close();
+ },
+ }),
+ $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 =
+ "";
+ }
+ },
+ }),
+ ]
+ ),
+ ];
+ }
- input(title, message) {
- return new Promise((resolve, reject) => {
- this.callback = resolve;
- this.show(`
+ input(title, message) {
+ return new Promise((resolve, reject) => {
+ this.callback = resolve;
+ this.show(`
${title}
`);
- });
- }
+ });
+ }
}
export class ConfirmDialog extends InfoDialog {
- callback = undefined;
+ callback = undefined;
- constructor() {
- super();
- }
+ constructor() {
+ super();
+ }
- createButtons() {
- return [
- $el(
- "div",
- {
- type: "div",
- style: {
- display: "flex",
- gap: "6px",
- justifyContent: "flex-end",
- width: "100%",
- },
- },
- [
- $el("button", {
- type: "button",
- textContent: "Close",
- onclick: () => {
- this.callback?.(false);
- this.close();
- },
- }),
- $el("button", {
- type: "button",
- textContent: "Confirm",
- style: {
- color: "green",
- },
- onclick: () => {
- this.callback?.(true);
- this.close();
- },
- }),
- ],
- ),
- ];
- }
+ createButtons() {
+ return [
+ $el(
+ "div",
+ {
+ type: "div",
+ style: {
+ display: "flex",
+ gap: "6px",
+ justifyContent: "flex-end",
+ width: "100%",
+ },
+ },
+ [
+ $el("button", {
+ type: "button",
+ textContent: "Close",
+ onclick: () => {
+ this.callback?.(false);
+ this.close();
+ },
+ }),
+ $el("button", {
+ type: "button",
+ textContent: "Confirm",
+ style: {
+ color: "green",
+ },
+ onclick: () => {
+ this.callback?.(true);
+ this.close();
+ },
+ }),
+ ]
+ ),
+ ];
+ }
- confirm(title, message) {
- return new Promise((resolve, reject) => {
- this.callback = resolve;
- this.show(`
+ confirm(title, message) {
+ return new Promise((resolve, reject) => {
+ this.callback = resolve;
+ this.show(`
${title}
${message}
`);
- });
- }
+ });
+ }
}
export const inputDialog = new InputDialog();
@@ -985,25 +1102,25 @@ export const confirmDialog = new ConfirmDialog();
* @returns {{endpoint: string, apiKey: string, displayName: string, environment?: string}} The deployment data.
*/
function getData(environment) {
- const deployOption =
- environment || localStorage.getItem("comfy_deploy_env") || "cloud";
- const data = localStorage.getItem("comfy_deploy_env_data_" + deployOption);
- if (!data) {
- if (deployOption == "cloud")
- return {
- endpoint: "https://www.comfydeploy.com",
- apiKey: "",
- };
- else
- return {
- endpoint: "http://localhost:3000",
- apiKey: "",
- };
- }
- return {
- ...JSON.parse(data),
- environment: deployOption,
- };
+ const deployOption =
+ environment || localStorage.getItem("comfy_deploy_env") || "cloud";
+ const data = localStorage.getItem("comfy_deploy_env_data_" + deployOption);
+ if (!data) {
+ if (deployOption == "cloud")
+ return {
+ endpoint: "https://www.comfydeploy.com",
+ apiKey: "",
+ };
+ else
+ return {
+ endpoint: "http://localhost:3000",
+ apiKey: "",
+ };
+ }
+ return {
+ ...JSON.parse(data),
+ environment: deployOption,
+ };
}
/**
@@ -1011,188 +1128,202 @@ function getData(environment) {
* @param {{endpoint: string, apiKey: string, displayName: string, environment?: string}} [data] - The environment to get the data for.
*/
function saveData(data) {
- localStorage.setItem(
- "comfy_deploy_env_data_" + data.environment,
- JSON.stringify(data),
- );
+ localStorage.setItem(
+ "comfy_deploy_env_data_" + data.environment,
+ JSON.stringify(data)
+ );
}
export class ConfigDialog extends ComfyDialog {
- container = null;
- poll = null;
- timeout = null;
+ container = null;
+ poll = null;
+ timeout = null;
- constructor() {
- super();
- this.element.classList.add("comfy-normal-modal");
- this.element.style.paddingBottom = "20px";
+ 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);
- }
-
- createButtons() {
- return [
- $el(
- "div",
- {
- type: "div",
- style: {
- display: "flex",
- gap: "6px",
- justifyContent: "flex-end",
- width: "100%",
- },
- onclick: () => {
- this.save();
- this.close();
- },
- },
- [
- $el("button", {
- type: "button",
- textContent: "Close",
- onclick: () => this.close(),
- }),
- $el("button", {
- type: "button",
- textContent: "Save",
- onclick: () => {
- this.save();
- this.close();
- },
- }),
- ],
- ),
- ];
- }
-
- close() {
- this.element.style.display = "none";
- clearInterval(this.poll);
- clearTimeout(this.timeout);
- }
-
- save(api_key, displayName) {
- const deployOption = this.container.querySelector("#deployOption").value;
- localStorage.setItem("comfy_deploy_env", deployOption);
-
- const endpoint = this.container.querySelector("#endpoint").value;
- const apiKey = api_key ?? this.container.querySelector("#apiKey").value;
-
- if (!displayName) {
- if (apiKey != getData().apiKey) {
- displayName = "Custom";
- } else {
- displayName = getData().displayName;
- }
+ this.container = document.createElement("div");
+ this.element
+ .querySelector(".comfy-modal-content")
+ .prepend(this.container);
}
- saveData({
- endpoint,
- apiKey,
- displayName,
- environment: deployOption,
- });
- }
+ createButtons() {
+ return [
+ $el(
+ "div",
+ {
+ type: "div",
+ style: {
+ display: "flex",
+ gap: "6px",
+ justifyContent: "flex-end",
+ width: "100%",
+ },
+ onclick: () => {
+ this.save();
+ this.close();
+ },
+ },
+ [
+ $el("button", {
+ type: "button",
+ textContent: "Close",
+ onclick: () => this.close(),
+ }),
+ $el("button", {
+ type: "button",
+ textContent: "Save",
+ onclick: () => {
+ this.save();
+ this.close();
+ },
+ }),
+ ]
+ ),
+ ];
+ }
- show() {
- this.container.style.color = "white";
+ close() {
+ this.element.style.display = "none";
+ clearInterval(this.poll);
+ clearTimeout(this.timeout);
+ }
- const data = getData();
+ save(api_key, displayName) {
+ const deployOption =
+ this.container.querySelector("#deployOption").value;
+ localStorage.setItem("comfy_deploy_env", deployOption);
- this.container.innerHTML = `
+ const endpoint = this.container.querySelector("#endpoint").value;
+ const apiKey = api_key ?? this.container.querySelector("#apiKey").value;
+
+ if (!displayName) {
+ if (apiKey != getData().apiKey) {
+ displayName = "Custom";
+ } else {
+ displayName = getData().displayName;
+ }
+ }
+
+ saveData({
+ endpoint,
+ apiKey,
+ displayName,
+ environment: deployOption,
+ });
+ }
+
+ show() {
+ this.container.style.color = "white";
+
+ const data = getData();
+
+ this.container.innerHTML = `
`;
- const button = this.container.querySelector("#loginButton");
- button.onclick = () => {
- this.save();
- const data = getData();
+ const button = this.container.querySelector("#loginButton");
+ button.onclick = () => {
+ this.save();
+ const data = getData();
- const uuid =
- Math.random().toString(36).substring(2, 15) +
- Math.random().toString(36).substring(2, 15);
- window.open(data.endpoint + "/auth-request/" + uuid, "_blank");
+ const uuid =
+ Math.random().toString(36).substring(2, 15) +
+ Math.random().toString(36).substring(2, 15);
+ window.open(data.endpoint + "/auth-request/" + uuid, "_blank");
- this.timeout = setTimeout(() => {
- clearInterval(poll);
- infoDialog.showMessage(
- "Timeout",
- "Wait too long for the response, please try re-login",
- );
- }, 30000); // Stop polling after 30 seconds
+ this.timeout = setTimeout(() => {
+ clearInterval(poll);
+ infoDialog.showMessage(
+ "Timeout",
+ "Wait too long for the response, please try re-login"
+ );
+ }, 30000); // Stop polling after 30 seconds
- this.poll = setInterval(() => {
- fetch(data.endpoint + "/api/auth-response/" + uuid)
- .then((response) => response.json())
- .then(async (json) => {
- if (json.api_key) {
- this.save(json.api_key, json.name);
- this.close();
- this.container.querySelector("#apiKey").value = json.api_key;
- // infoDialog.show();
- clearInterval(this.poll);
- clearTimeout(this.timeout);
- // Refresh dialog
- const a = await confirmDialog.confirm(
- "Authenticated",
- `
You will be able to upload workflow to
`,
- );
- configDialog.show();
- }
- })
- .catch((error) => {
- console.error("Error:", error);
- clearInterval(this.poll);
- clearTimeout(this.timeout);
- infoDialog.showMessage("Error", error);
- });
- }, 2000);
- };
+ this.poll = setInterval(() => {
+ fetch(data.endpoint + "/api/auth-response/" + uuid)
+ .then((response) => response.json())
+ .then(async (json) => {
+ if (json.api_key) {
+ this.save(json.api_key, json.name);
+ this.close();
+ this.container.querySelector("#apiKey").value =
+ json.api_key;
+ // infoDialog.show();
+ clearInterval(this.poll);
+ clearTimeout(this.timeout);
+ // Refresh dialog
+ const a = await confirmDialog.confirm(
+ "Authenticated",
+ `
You will be able to upload workflow to
`
+ );
+ configDialog.show();
+ }
+ })
+ .catch((error) => {
+ console.error("Error:", error);
+ clearInterval(this.poll);
+ clearTimeout(this.timeout);
+ infoDialog.showMessage("Error", error);
+ });
+ }, 2000);
+ };
- const apiKeyInput = this.container.querySelector("#apiKey");
- apiKeyInput.addEventListener("paste", (e) => {
- e.stopPropagation();
- });
+ const apiKeyInput = this.container.querySelector("#apiKey");
+ apiKeyInput.addEventListener("paste", (e) => {
+ e.stopPropagation();
+ });
- const deployOption = this.container.querySelector("#deployOption");
- const container = this.container;
- deployOption.addEventListener("change", function () {
- const selectedOption = this.value;
- const data = getData(selectedOption);
- localStorage.setItem("comfy_deploy_env", selectedOption);
+ const deployOption = this.container.querySelector("#deployOption");
+ 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;
- });
+ container.querySelector("#endpoint").value = data.endpoint;
+ container.querySelector("#apiKey").value = data.apiKey;
+ });
- this.element.style.display = "flex";
- this.element.style.zIndex = 1001;
- }
+ this.element.style.display = "flex";
+ this.element.style.zIndex = 1001;
+ }
}
export const configDialog = new ConfigDialog();