diff --git a/src_web/comfyui/config.ts b/src_web/comfyui/config.ts index 407094d..cdb7096 100644 --- a/src_web/comfyui/config.ts +++ b/src_web/comfyui/config.ts @@ -6,7 +6,7 @@ import { RgthreeDialog, RgthreeDialogOptions } from "rgthree/common/dialog.js"; import { rgthreeApi } from "rgthree/common/rgthree_api.js"; import { getObjectValue, setObjectValue } from "rgthree/common/shared_utils.js"; import { createElement as $el, querySelectorAll as $$ } from "rgthree/common/utils_dom.js"; -import { logoRgthree } from "rgthree/common/media/svgs.js"; +import { checkmark, logoRgthree } from "rgthree/common/media/svgs.js"; import { rgthree } from "./rgthree.js"; /** Types of config used as a hint for the form handling. */ @@ -198,7 +198,7 @@ export class RgthreeConfigDialog extends RgthreeDialog { this.close(); rgthree.showMessage({ id: "config-success", - message: "Successfully saved rgthree-comfy config!", + message: `${checkmark} Successfully saved rgthree-comfy settings!`, timeout: 4000, }); ($$(".save-button", this.element)[0] as HTMLButtonElement).disabled = true; diff --git a/src_web/comfyui/rgthree.css b/src_web/comfyui/rgthree.css index e4d548d..7c2aa7f 100644 --- a/src_web/comfyui/rgthree.css +++ b/src_web/comfyui/rgthree.css @@ -52,6 +52,20 @@ font-family: Arial, sans-serif; font-size: 14px; } +.rgthree-top-messages-container > div > div > span { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; +} +.rgthree-top-messages-container > div > div > span svg { + width: 20px; + height: auto; + margin-right: 8px; +} +.rgthree-top-messages-container > div > div > span svg.icon-checkmark { + fill: #2e9720; +} .rgthree-top-messages-container [type="warn"]::before { content: "⚠️"; @@ -394,12 +408,16 @@ body.rgthree-dialog-open > *:not(.rgthree-dialog):not(.rgthree-top-messages-cont margin-right: 16px; } + +.litegraph.litecontextmenu .litemenu-title .rgthree-contextmenu-title-rgthree-comfy, .litegraph.litecontextmenu .litemenu-entry.rgthree-contextmenu-item { display: flex; flex-direction: row; align-items: center; justify-content: start; } + +.litegraph.litecontextmenu .litemenu-title .rgthree-contextmenu-title-rgthree-comfy svg, .litegraph.litecontextmenu .litemenu-entry.rgthree-contextmenu-item svg { fill: currentColor; width: auto; @@ -410,9 +428,10 @@ body.rgthree-dialog-open > *:not(.rgthree-dialog):not(.rgthree-top-messages-cont fill: rgb(227, 179, 65); } +.litegraph.litecontextmenu .litemenu-title .rgthree-contextmenu-title-rgthree-comfy, .litegraph.litecontextmenu .litemenu-entry.rgthree-contextmenu-label { color: #dde; - background-color: #090909 !important; + background-color: #212121 !important; margin: 0; padding: 2px; cursor: default; @@ -420,6 +439,13 @@ body.rgthree-dialog-open > *:not(.rgthree-dialog):not(.rgthree-top-messages-cont padding: 4px; font-weight: bold; } +.litegraph.litecontextmenu .litemenu-title .rgthree-contextmenu-title-rgthree-comfy { + font-size: 1.1em; + color: #fff; + background-color: #090909 !important; + justify-content: center; + padding: 4px 8px; +} rgthree-progress-bar { display: block; diff --git a/src_web/comfyui/rgthree.ts b/src_web/comfyui/rgthree.ts index da190a7..f758ccf 100644 --- a/src_web/comfyui/rgthree.ts +++ b/src_web/comfyui/rgthree.ts @@ -1,8 +1,11 @@ -import { - type LGraphCanvas as TLGraphCanvas, - type LGraphNode, - type SerializedLGraphNode, - type serializedLGraph, +import type { + LGraphCanvas as TLGraphCanvas, + LGraphNode, + SerializedLGraphNode, + serializedLGraph, + LiteGraph as TLiteGraph, + ContextMenuItem, + LGraph as TLGraph, } from "typings/litegraph.js"; // @ts-ignore import { app } from "../../scripts/app.js"; @@ -16,9 +19,9 @@ import { replaceNode, waitForCanvas, waitForGraph } from "./utils.js"; import { NodeTypesString } from "./constants.js"; import { RgthreeProgressBar } from "rgthree/common/progress_bar.js"; import { RgthreeConfigDialog } from "./config.js"; -import { querySelectorAll as $$ } from "rgthree/common/utils_dom.js"; import { iconGear, iconReplace, iconStarFilled, logoRgthree } from "rgthree/common/media/svgs.js"; +declare const LiteGraph: typeof TLiteGraph; declare const LGraphCanvas: typeof TLGraphCanvas; export enum LogLevel { @@ -139,6 +142,7 @@ class Rgthree extends EventTarget { /** Exposes the ComfyUI api instance on rgthree. */ readonly api = api; private settingsDialog: RgthreeConfigDialog | null = null; + private progressBarEl: RgthreeProgressBar | null = null; /** Are any functional keys pressed in this given moment? */ ctrlKey = false; @@ -154,7 +158,7 @@ class Rgthree extends EventTarget { processingQueue = false; loadingApiJson = false; - replacingReroute: number|null = null; + replacingReroute: number | null = null; // Comfy/LiteGraph states so nodes and tell what the hell is going on. canvasCurrentlyCopyingToClipboard = false; @@ -192,19 +196,55 @@ class Rgthree extends EventTarget { * Initializes the top progress bar, if it's configured. */ initializeProgressBar() { - let bar = $$(RgthreeProgressBar.NAME)[0]; if (CONFIG_SERVICE.getConfigValue("features.progress_bar.enabled")) { - if (!bar) { - bar = RgthreeProgressBar.create(); - document.body.appendChild(bar); + if (!this.progressBarEl) { + this.progressBarEl = RgthreeProgressBar.create(); + + this.progressBarEl.addEventListener("contextmenu", async (e) => { + e.stopPropagation(); + e.preventDefault(); + }); + + this.progressBarEl.addEventListener("pointerdown", async (e) => { + LiteGraph.closeAllContextMenus(); + if (e.button == 2) { + const canvas = await waitForCanvas(); + new LiteGraph.ContextMenu( + this.getRgthreeContextMenuItems(), + { + title: `
`, + left: e.clientX, + top: 5, + }, + canvas.getCanvasWindow(), + ); + return; + } + if (e.button == 0) { + const nodeId = this.progressBarEl?.currentNodeId; + if (nodeId) { + const [canvas, graph] = await Promise.all([waitForCanvas(), waitForGraph()]); + const node = graph.getNodeById(Number(nodeId)); + if (node) { + canvas.centerOnNode(node); + e.stopPropagation(); + e.preventDefault(); + } + } + return; + } + }); + } + if (!this.progressBarEl!.parentElement) { + document.body.appendChild(this.progressBarEl); } const height = CONFIG_SERVICE.getConfigValue("features.progress_bar.height") || 14; - bar.style.height = `${height}px`; + this.progressBarEl.style.height = `${height}px`; const fontSize = Math.max(10, Number(height) - 10); - bar.style.fontSize = `${fontSize}px`; - bar.style.fontWeight = fontSize <= 12 ? 'bold' : 'normal'; + this.progressBarEl.style.fontSize = `${fontSize}px`; + this.progressBarEl.style.fontWeight = fontSize <= 12 ? "bold" : "normal"; } else { - bar?.remove(); + this.progressBarEl?.remove(); } } @@ -260,79 +300,18 @@ class Rgthree extends EventTarget { * Initializes hooks specific to an rgthree-comfy context menu on the root menu. */ private async initializeContextMenu() { - const graph = await waitForGraph(); const that = this; - setTimeout(() => { + setTimeout(async () => { const getCanvasMenuOptions = LGraphCanvas.prototype.getCanvasMenuOptions; LGraphCanvas.prototype.getCanvasMenuOptions = function (...args: any[]) { const options = getCanvasMenuOptions.apply(this, [...args] as any); - const selectedNodes = Object.values(this.selected_nodes || {}); - let rerouteNodes: LGraphNode[] = []; - if (selectedNodes.length) { - rerouteNodes = selectedNodes.filter((n) => n.type === "Reroute"); - } else { - rerouteNodes = graph._nodes.filter((n) => n.type == "Reroute"); - } - const rerouteLabel = selectedNodes.length ? "selected" : "all"; - options.push(null); // Divider options.push({ content: logoRgthree + `rgthree-comfy`, - className: "rgthree-contextmenu-item rgthree-contextmenu-main-rgthree-comfy", + className: "rgthree-contextmenu-item rgthree-contextmenu-main-item-rgthree-comfy", submenu: { - options: [ - { - content: "Actions", - disabled: true, - className: "rgthree-contextmenu-item rgthree-contextmenu-label", - }, - { - content: iconGear + "Open rgthree-comfy Settings", - disabled: !!that.settingsDialog, - className: "rgthree-contextmenu-item", - callback: (...args: any[]) => { - that.settingsDialog = new RgthreeConfigDialog().show(); - that.settingsDialog.addEventListener("close", (e) => { - that.settingsDialog = null; - }); - }, - }, - { - content: iconReplace + ` Convert ${rerouteLabel} Reroutes`, - disabled: !rerouteNodes.length, - className: "rgthree-contextmenu-item", - callback: (...args: any[]) => { - const msg = - `Convert ${rerouteLabel} ComfyUI Reroutes to Reroute (rgthree) nodes? \n` + - `(First save a copy of your workflow & check reroute connections afterwards)`; - if (!window.confirm(msg)) { - return; - } - (async () => { - for (const node of [...rerouteNodes]) { - if (node.type == "Reroute") { - that.replacingReroute = node.id; - await replaceNode(node, NodeTypesString.REROUTE); - that.replacingReroute = null; - } - } - })(); - }, - }, - { - content: "More...", - disabled: true, - className: "rgthree-contextmenu-item rgthree-contextmenu-label", - }, - { - content: iconStarFilled + "Star on Github", - className: "rgthree-contextmenu-item rgthree-contextmenu-github", - callback: (...args: any[]) => { - window.open("https://github.com/rgthree/rgthree-comfy", "_blank"); - }, - }, - ], + options: that.getRgthreeContextMenuItems(), }, }); @@ -341,6 +320,74 @@ class Rgthree extends EventTarget { }, 1000); } + /** + * Returns the standard menu items for an rgthree-comfy context menu. + */ + private getRgthreeContextMenuItems(): ContextMenuItem[] { + const [canvas, graph] = [app.canvas as TLGraphCanvas, app.graph as TLGraph]; + const selectedNodes = Object.values(canvas.selected_nodes || {}); + let rerouteNodes: LGraphNode[] = []; + if (selectedNodes.length) { + rerouteNodes = selectedNodes.filter((n) => n.type === "Reroute"); + } else { + rerouteNodes = graph._nodes.filter((n) => n.type == "Reroute"); + } + const rerouteLabel = selectedNodes.length ? "selected" : "all"; + + return [ + { + content: "Actions", + disabled: true, + className: "rgthree-contextmenu-item rgthree-contextmenu-label", + }, + { + content: iconGear + "Settings (rgthree-comfy)", + disabled: !!this.settingsDialog, + className: "rgthree-contextmenu-item", + callback: (...args: any[]) => { + this.settingsDialog = new RgthreeConfigDialog().show(); + this.settingsDialog.addEventListener("close", (e) => { + this.settingsDialog = null; + }); + }, + }, + { + content: iconReplace + ` Convert ${rerouteLabel} Reroutes`, + disabled: !rerouteNodes.length, + className: "rgthree-contextmenu-item", + callback: (...args: any[]) => { + const msg = + `Convert ${rerouteLabel} ComfyUI Reroutes to Reroute (rgthree) nodes? \n` + + `(First save a copy of your workflow & check reroute connections afterwards)`; + if (!window.confirm(msg)) { + return; + } + (async () => { + for (const node of [...rerouteNodes]) { + if (node.type == "Reroute") { + this.replacingReroute = node.id; + await replaceNode(node, NodeTypesString.REROUTE); + this.replacingReroute = null; + } + } + })(); + }, + }, + { + content: "More...", + disabled: true, + className: "rgthree-contextmenu-item rgthree-contextmenu-label", + }, + { + content: iconStarFilled + "Star on Github", + className: "rgthree-contextmenu-item rgthree-contextmenu-github", + callback: (...args: any[]) => { + window.open("https://github.com/rgthree/rgthree-comfy", "_blank"); + }, + }, + ]; + } + /** * Initialize a bunch of hooks into ComfyUI and/or LiteGraph itself so we can either keep state or * context on what's happening so nodes can respond appropriately. This is usually to fix broken @@ -516,7 +563,7 @@ class Rgthree extends EventTarget { messageContainer.setAttribute("type", data.type || "info"); const message = document.createElement("span"); - message.innerText = data.message; + message.innerHTML = data.message; messageContainer.appendChild(message); for (let a = 0; a < (data.actions || []).length; a++) { diff --git a/src_web/common/media/svgs.ts b/src_web/common/media/svgs.ts index 3093c99..c7b96e4 100644 --- a/src_web/common/media/svgs.ts +++ b/src_web/common/media/svgs.ts @@ -29,4 +29,11 @@ export const iconReplace = ` export const iconGear = ` ` \ No newline at end of file + ` + +export const checkmark = ` + `; \ No newline at end of file diff --git a/src_web/common/progress_bar.ts b/src_web/common/progress_bar.ts index f3d309a..523f9d6 100644 --- a/src_web/common/progress_bar.ts +++ b/src_web/common/progress_bar.ts @@ -241,18 +241,20 @@ export class RgthreeProgressBar extends HTMLElement { private connected: boolean = false; + /** The currentNodeId so outside callers can see what we're currently executing against. */ + get currentNodeId() { + const prompt = this.currentPromptExecution; + const nodeId = prompt?.errorDetails?.node_id || prompt?.currentlyExecuting?.nodeId; + return nodeId || null; + } + constructor() { super(); } - private maybeGetComfyGraph(): TLGraph | null { - return ((window as any)?.app?.graph as TLGraph) || null; - } - private maybeGetComfyCanvas(): TLGraphCanvas | null { - return ((window as any)?.app?.canvas as TLGraphCanvas) || null; - } - private onProgressUpdate(e: CustomEvent<{ queue: number; prompt: PromptExecution }>) { + if (!this.connected) return; + const prompt = e.detail.prompt; this.currentPromptExecution = prompt; @@ -313,10 +315,17 @@ export class RgthreeProgressBar extends HTMLElement { } connectedCallback() { + if (!this.connected) { + SERVICE.addEventListener("progress-update", this.onProgressUpdateBound as EventListener); + this.connected = true; + } + // We were already connected, so we just need to reset. if (this.shadow) { + this.progressTextEl.innerText = 'Idle'; + this.progressNodesEl.style.width = `0%`; + this.progressStepsEl.style.width = `0%`; return; } - SERVICE.addEventListener("progress-update", this.onProgressUpdateBound as EventListener); this.shadow = this.attachShadow({ mode: "open" }); const sheet = new CSSStyleSheet(); @@ -403,12 +412,6 @@ export class RgthreeProgressBar extends HTMLElement { this.progressTextEl = document.createElement("span"); this.progressTextEl.innerText = "Idle"; this.shadow.appendChild(this.progressTextEl); - - overlayEl.addEventListener("click", (e: MouseEvent) => { - this.onClick(e); - }); - - this.connected = true; } disconnectedCallback() { @@ -416,28 +419,6 @@ export class RgthreeProgressBar extends HTMLElement { SERVICE.removeEventListener("progress-update", this.onProgressUpdateBound as EventListener); } - onClick(e: PointerEvent | MouseEvent) { - const prompt = this.currentPromptExecution; - const nodeId = prompt?.errorDetails?.node_id || prompt?.currentlyExecuting?.nodeId; - if (!nodeId) return; - - const graph = this.maybeGetComfyGraph(); - const canvas = this.maybeGetComfyCanvas(); - if (graph && canvas) { - const node = graph.getNodeById(Number(nodeId)); - if (node) { - canvas.centerOnNode(node); - e.stopPropagation(); - e.preventDefault(); - } - } - } - - updateProgress() { - if (!this.shadow) { - return; - } - } } customElements.define(RgthreeProgressBar.NAME, RgthreeProgressBar); diff --git a/src_web/typings/litegraph.d.ts b/src_web/typings/litegraph.d.ts index 80fe05e..afb0a13 100644 --- a/src_web/typings/litegraph.d.ts +++ b/src_web/typings/litegraph.d.ts @@ -188,6 +188,10 @@ export interface IContextMenuOptions { autoopen?: boolean; title?: string; extra?: any; + // @rgthree + left?: number; + // @rgthree + top?: number; } export type ContextMenuItem = IContextMenuItem | null; @@ -392,6 +396,8 @@ export const LiteGraph: { ContextMenu: typeof ContextMenu; extendClass(target: A, origin: B): A & B; getParameterNames(func: string): string[]; + // @rgthree + closeAllContextMenus(ref_window?: Window): void; }; export type serializedLGraph< diff --git a/web/comfyui/config.js b/web/comfyui/config.js index c1b1e29..24105a6 100644 --- a/web/comfyui/config.js +++ b/web/comfyui/config.js @@ -4,7 +4,7 @@ import { RgthreeDialog } from "../../rgthree/common/dialog.js"; import { rgthreeApi } from "../../rgthree/common/rgthree_api.js"; import { getObjectValue, setObjectValue } from "../../rgthree/common/shared_utils.js"; import { createElement as $el, querySelectorAll as $$ } from "../../rgthree/common/utils_dom.js"; -import { logoRgthree } from "../../rgthree/common/media/svgs.js"; +import { checkmark, logoRgthree } from "../../rgthree/common/media/svgs.js"; import { rgthree } from "./rgthree.js"; var ConfigType; (function (ConfigType) { @@ -156,7 +156,7 @@ export class RgthreeConfigDialog extends RgthreeDialog { this.close(); rgthree.showMessage({ id: "config-success", - message: "Successfully saved rgthree-comfy config!", + message: `${checkmark} Successfully saved rgthree-comfy settings!`, timeout: 4000, }); $$(".save-button", this.element)[0].disabled = true; diff --git a/web/comfyui/rgthree.css b/web/comfyui/rgthree.css index e4d548d..7c2aa7f 100644 --- a/web/comfyui/rgthree.css +++ b/web/comfyui/rgthree.css @@ -52,6 +52,20 @@ font-family: Arial, sans-serif; font-size: 14px; } +.rgthree-top-messages-container > div > div > span { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; +} +.rgthree-top-messages-container > div > div > span svg { + width: 20px; + height: auto; + margin-right: 8px; +} +.rgthree-top-messages-container > div > div > span svg.icon-checkmark { + fill: #2e9720; +} .rgthree-top-messages-container [type="warn"]::before { content: "⚠️"; @@ -394,12 +408,16 @@ body.rgthree-dialog-open > *:not(.rgthree-dialog):not(.rgthree-top-messages-cont margin-right: 16px; } + +.litegraph.litecontextmenu .litemenu-title .rgthree-contextmenu-title-rgthree-comfy, .litegraph.litecontextmenu .litemenu-entry.rgthree-contextmenu-item { display: flex; flex-direction: row; align-items: center; justify-content: start; } + +.litegraph.litecontextmenu .litemenu-title .rgthree-contextmenu-title-rgthree-comfy svg, .litegraph.litecontextmenu .litemenu-entry.rgthree-contextmenu-item svg { fill: currentColor; width: auto; @@ -410,9 +428,10 @@ body.rgthree-dialog-open > *:not(.rgthree-dialog):not(.rgthree-top-messages-cont fill: rgb(227, 179, 65); } +.litegraph.litecontextmenu .litemenu-title .rgthree-contextmenu-title-rgthree-comfy, .litegraph.litecontextmenu .litemenu-entry.rgthree-contextmenu-label { color: #dde; - background-color: #090909 !important; + background-color: #212121 !important; margin: 0; padding: 2px; cursor: default; @@ -420,6 +439,13 @@ body.rgthree-dialog-open > *:not(.rgthree-dialog):not(.rgthree-top-messages-cont padding: 4px; font-weight: bold; } +.litegraph.litecontextmenu .litemenu-title .rgthree-contextmenu-title-rgthree-comfy { + font-size: 1.1em; + color: #fff; + background-color: #090909 !important; + justify-content: center; + padding: 4px 8px; +} rgthree-progress-bar { display: block; diff --git a/web/comfyui/rgthree.js b/web/comfyui/rgthree.js index e04f449..38a1460 100644 --- a/web/comfyui/rgthree.js +++ b/web/comfyui/rgthree.js @@ -7,7 +7,6 @@ import { replaceNode, waitForCanvas, waitForGraph } from "./utils.js"; import { NodeTypesString } from "./constants.js"; import { RgthreeProgressBar } from "../../rgthree/common/progress_bar.js"; import { RgthreeConfigDialog } from "./config.js"; -import { querySelectorAll as $$ } from "../../rgthree/common/utils_dom.js"; import { iconGear, iconReplace, iconStarFilled, logoRgthree } from "../../rgthree/common/media/svgs.js"; export var LogLevel; (function (LogLevel) { @@ -82,6 +81,7 @@ class Rgthree extends EventTarget { super(); this.api = api; this.settingsDialog = null; + this.progressBarEl = null; this.ctrlKey = false; this.altKey = false; this.metaKey = false; @@ -117,20 +117,52 @@ class Rgthree extends EventTarget { })); } initializeProgressBar() { - let bar = $$(RgthreeProgressBar.NAME)[0]; + var _a; if (CONFIG_SERVICE.getConfigValue("features.progress_bar.enabled")) { - if (!bar) { - bar = RgthreeProgressBar.create(); - document.body.appendChild(bar); + if (!this.progressBarEl) { + this.progressBarEl = RgthreeProgressBar.create(); + this.progressBarEl.addEventListener("contextmenu", async (e) => { + e.stopPropagation(); + e.preventDefault(); + }); + this.progressBarEl.addEventListener("pointerdown", async (e) => { + var _a; + LiteGraph.closeAllContextMenus(); + if (e.button == 2) { + const canvas = await waitForCanvas(); + new LiteGraph.ContextMenu(this.getRgthreeContextMenuItems(), { + title: ``, + left: e.clientX, + top: 5, + }, canvas.getCanvasWindow()); + return; + } + if (e.button == 0) { + const nodeId = (_a = this.progressBarEl) === null || _a === void 0 ? void 0 : _a.currentNodeId; + if (nodeId) { + const [canvas, graph] = await Promise.all([waitForCanvas(), waitForGraph()]); + const node = graph.getNodeById(Number(nodeId)); + if (node) { + canvas.centerOnNode(node); + e.stopPropagation(); + e.preventDefault(); + } + } + return; + } + }); + } + if (!this.progressBarEl.parentElement) { + document.body.appendChild(this.progressBarEl); } const height = CONFIG_SERVICE.getConfigValue("features.progress_bar.height") || 14; - bar.style.height = `${height}px`; + this.progressBarEl.style.height = `${height}px`; const fontSize = Math.max(10, Number(height) - 10); - bar.style.fontSize = `${fontSize}px`; - bar.style.fontWeight = fontSize <= 12 ? 'bold' : 'normal'; + this.progressBarEl.style.fontSize = `${fontSize}px`; + this.progressBarEl.style.fontWeight = fontSize <= 12 ? "bold" : "normal"; } else { - bar === null || bar === void 0 ? void 0 : bar.remove(); + (_a = this.progressBarEl) === null || _a === void 0 ? void 0 : _a.remove(); } } async initializeGraphAndCanvasHooks() { @@ -157,83 +189,86 @@ class Rgthree extends EventTarget { }; } async initializeContextMenu() { - const graph = await waitForGraph(); const that = this; - setTimeout(() => { + setTimeout(async () => { const getCanvasMenuOptions = LGraphCanvas.prototype.getCanvasMenuOptions; LGraphCanvas.prototype.getCanvasMenuOptions = function (...args) { const options = getCanvasMenuOptions.apply(this, [...args]); - const selectedNodes = Object.values(this.selected_nodes || {}); - let rerouteNodes = []; - if (selectedNodes.length) { - rerouteNodes = selectedNodes.filter((n) => n.type === "Reroute"); - } - else { - rerouteNodes = graph._nodes.filter((n) => n.type == "Reroute"); - } - const rerouteLabel = selectedNodes.length ? "selected" : "all"; options.push(null); options.push({ content: logoRgthree + `rgthree-comfy`, - className: "rgthree-contextmenu-item rgthree-contextmenu-main-rgthree-comfy", + className: "rgthree-contextmenu-item rgthree-contextmenu-main-item-rgthree-comfy", submenu: { - options: [ - { - content: "Actions", - disabled: true, - className: "rgthree-contextmenu-item rgthree-contextmenu-label", - }, - { - content: iconGear + "Open rgthree-comfy Settings", - disabled: !!that.settingsDialog, - className: "rgthree-contextmenu-item", - callback: (...args) => { - that.settingsDialog = new RgthreeConfigDialog().show(); - that.settingsDialog.addEventListener("close", (e) => { - that.settingsDialog = null; - }); - }, - }, - { - content: iconReplace + ` Convert ${rerouteLabel} Reroutes`, - disabled: !rerouteNodes.length, - className: "rgthree-contextmenu-item", - callback: (...args) => { - const msg = `Convert ${rerouteLabel} ComfyUI Reroutes to Reroute (rgthree) nodes? \n` + - `(First save a copy of your workflow & check reroute connections afterwards)`; - if (!window.confirm(msg)) { - return; - } - (async () => { - for (const node of [...rerouteNodes]) { - if (node.type == "Reroute") { - that.replacingReroute = node.id; - await replaceNode(node, NodeTypesString.REROUTE); - that.replacingReroute = null; - } - } - })(); - }, - }, - { - content: "More...", - disabled: true, - className: "rgthree-contextmenu-item rgthree-contextmenu-label", - }, - { - content: iconStarFilled + "Star on Github", - className: "rgthree-contextmenu-item rgthree-contextmenu-github", - callback: (...args) => { - window.open("https://github.com/rgthree/rgthree-comfy", "_blank"); - }, - }, - ], + options: that.getRgthreeContextMenuItems(), }, }); return options; }; }, 1000); } + getRgthreeContextMenuItems() { + const [canvas, graph] = [app.canvas, app.graph]; + const selectedNodes = Object.values(canvas.selected_nodes || {}); + let rerouteNodes = []; + if (selectedNodes.length) { + rerouteNodes = selectedNodes.filter((n) => n.type === "Reroute"); + } + else { + rerouteNodes = graph._nodes.filter((n) => n.type == "Reroute"); + } + const rerouteLabel = selectedNodes.length ? "selected" : "all"; + return [ + { + content: "Actions", + disabled: true, + className: "rgthree-contextmenu-item rgthree-contextmenu-label", + }, + { + content: iconGear + "Settings (rgthree-comfy)", + disabled: !!this.settingsDialog, + className: "rgthree-contextmenu-item", + callback: (...args) => { + this.settingsDialog = new RgthreeConfigDialog().show(); + this.settingsDialog.addEventListener("close", (e) => { + this.settingsDialog = null; + }); + }, + }, + { + content: iconReplace + ` Convert ${rerouteLabel} Reroutes`, + disabled: !rerouteNodes.length, + className: "rgthree-contextmenu-item", + callback: (...args) => { + const msg = `Convert ${rerouteLabel} ComfyUI Reroutes to Reroute (rgthree) nodes? \n` + + `(First save a copy of your workflow & check reroute connections afterwards)`; + if (!window.confirm(msg)) { + return; + } + (async () => { + for (const node of [...rerouteNodes]) { + if (node.type == "Reroute") { + this.replacingReroute = node.id; + await replaceNode(node, NodeTypesString.REROUTE); + this.replacingReroute = null; + } + } + })(); + }, + }, + { + content: "More...", + disabled: true, + className: "rgthree-contextmenu-item rgthree-contextmenu-label", + }, + { + content: iconStarFilled + "Star on Github", + className: "rgthree-contextmenu-item rgthree-contextmenu-github", + callback: (...args) => { + window.open("https://github.com/rgthree/rgthree-comfy", "_blank"); + }, + }, + ]; + } initializeComfyUIHooks() { const rgthree = this; const queuePrompt = app.queuePrompt; @@ -361,7 +396,7 @@ class Rgthree extends EventTarget { const messageContainer = document.createElement("div"); messageContainer.setAttribute("type", data.type || "info"); const message = document.createElement("span"); - message.innerText = data.message; + message.innerHTML = data.message; messageContainer.appendChild(message); for (let a = 0; a < (data.actions || []).length; a++) { const action = data.actions[a]; diff --git a/web/common/media/svgs.js b/web/common/media/svgs.js index ff819f1..9f717b5 100644 --- a/web/common/media/svgs.js +++ b/web/common/media/svgs.js @@ -24,3 +24,9 @@ export const iconGear = ` `; +export const checkmark = ` + `; diff --git a/web/common/progress_bar.js b/web/common/progress_bar.js index 6530d52..dd37bc8 100644 --- a/web/common/progress_bar.js +++ b/web/common/progress_bar.js @@ -155,6 +155,12 @@ export class RgthreeProgressBar extends HTMLElement { static create() { return document.createElement(RgthreeProgressBar.NAME); } + get currentNodeId() { + var _a, _b; + const prompt = this.currentPromptExecution; + const nodeId = ((_a = prompt === null || prompt === void 0 ? void 0 : prompt.errorDetails) === null || _a === void 0 ? void 0 : _a.node_id) || ((_b = prompt === null || prompt === void 0 ? void 0 : prompt.currentlyExecuting) === null || _b === void 0 ? void 0 : _b.nodeId); + return nodeId || null; + } constructor() { super(); this.shadow = null; @@ -162,16 +168,10 @@ export class RgthreeProgressBar extends HTMLElement { this.onProgressUpdateBound = this.onProgressUpdate.bind(this); this.connected = false; } - maybeGetComfyGraph() { - var _a; - return ((_a = window === null || window === void 0 ? void 0 : window.app) === null || _a === void 0 ? void 0 : _a.graph) || null; - } - maybeGetComfyCanvas() { - var _a; - return ((_a = window === null || window === void 0 ? void 0 : window.app) === null || _a === void 0 ? void 0 : _a.canvas) || null; - } onProgressUpdate(e) { var _a, _b, _c, _d; + if (!this.connected) + return; const prompt = e.detail.prompt; this.currentPromptExecution = prompt; if (prompt === null || prompt === void 0 ? void 0 : prompt.errorDetails) { @@ -222,10 +222,16 @@ export class RgthreeProgressBar extends HTMLElement { } } connectedCallback() { + if (!this.connected) { + SERVICE.addEventListener("progress-update", this.onProgressUpdateBound); + this.connected = true; + } if (this.shadow) { + this.progressTextEl.innerText = 'Idle'; + this.progressNodesEl.style.width = `0%`; + this.progressStepsEl.style.width = `0%`; return; } - SERVICE.addEventListener("progress-update", this.onProgressUpdateBound); this.shadow = this.attachShadow({ mode: "open" }); const sheet = new CSSStyleSheet(); sheet.replaceSync(` @@ -307,37 +313,11 @@ export class RgthreeProgressBar extends HTMLElement { this.progressTextEl = document.createElement("span"); this.progressTextEl.innerText = "Idle"; this.shadow.appendChild(this.progressTextEl); - overlayEl.addEventListener("click", (e) => { - this.onClick(e); - }); - this.connected = true; } disconnectedCallback() { this.connected = false; SERVICE.removeEventListener("progress-update", this.onProgressUpdateBound); } - onClick(e) { - var _a, _b; - const prompt = this.currentPromptExecution; - const nodeId = ((_a = prompt === null || prompt === void 0 ? void 0 : prompt.errorDetails) === null || _a === void 0 ? void 0 : _a.node_id) || ((_b = prompt === null || prompt === void 0 ? void 0 : prompt.currentlyExecuting) === null || _b === void 0 ? void 0 : _b.nodeId); - if (!nodeId) - return; - const graph = this.maybeGetComfyGraph(); - const canvas = this.maybeGetComfyCanvas(); - if (graph && canvas) { - const node = graph.getNodeById(Number(nodeId)); - if (node) { - canvas.centerOnNode(node); - e.stopPropagation(); - e.preventDefault(); - } - } - } - updateProgress() { - if (!this.shadow) { - return; - } - } } RgthreeProgressBar.NAME = "rgthree-progress-bar"; customElements.define(RgthreeProgressBar.NAME, RgthreeProgressBar);