import { app } from "../../scripts/app.js"; import { api } from "../../scripts/api.js"; import { $el, ComfyDialog } from "../../scripts/ui.js"; function internalCustomConfirm(message, confirmMessage, cancelMessage) { return new Promise((resolve) => { // transparent bg const modalOverlay = document.createElement('div'); modalOverlay.style.position = 'fixed'; modalOverlay.style.top = 0; modalOverlay.style.left = 0; modalOverlay.style.width = '100%'; modalOverlay.style.height = '100%'; modalOverlay.style.backgroundColor = 'rgba(0, 0, 0, 0.8)'; modalOverlay.style.display = 'flex'; modalOverlay.style.alignItems = 'center'; modalOverlay.style.justifyContent = 'center'; modalOverlay.style.zIndex = '1101'; // Modal window container (dark bg) const modalDialog = document.createElement('div'); modalDialog.style.backgroundColor = '#333'; modalDialog.style.padding = '20px'; modalDialog.style.borderRadius = '4px'; modalDialog.style.maxWidth = '400px'; modalDialog.style.width = '80%'; modalDialog.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.5)'; modalDialog.style.color = '#fff'; // Display message const modalMessage = document.createElement('p'); modalMessage.textContent = message; modalMessage.style.margin = '0'; modalMessage.style.padding = '0 0 20px'; modalMessage.style.wordBreak = 'keep-all'; // Button container const modalButtons = document.createElement('div'); modalButtons.style.display = 'flex'; modalButtons.style.justifyContent = 'flex-end'; // Confirm button (green) const confirmButton = document.createElement('button'); if(confirmMessage) confirmButton.textContent = confirmMessage; else confirmButton.textContent = 'Confirm'; confirmButton.style.marginLeft = '10px'; confirmButton.style.backgroundColor = '#28a745'; // green confirmButton.style.color = '#fff'; confirmButton.style.border = 'none'; confirmButton.style.padding = '6px 12px'; confirmButton.style.borderRadius = '4px'; confirmButton.style.cursor = 'pointer'; confirmButton.style.fontWeight = 'bold'; // Cancel button (red) const cancelButton = document.createElement('button'); if(cancelMessage) cancelButton.textContent = cancelMessage; else cancelButton.textContent = 'Cancel'; cancelButton.style.marginLeft = '10px'; cancelButton.style.backgroundColor = '#dc3545'; // red cancelButton.style.color = '#fff'; cancelButton.style.border = 'none'; cancelButton.style.padding = '6px 12px'; cancelButton.style.borderRadius = '4px'; cancelButton.style.cursor = 'pointer'; cancelButton.style.fontWeight = 'bold'; const closeModal = () => { document.body.removeChild(modalOverlay); }; confirmButton.addEventListener('click', () => { closeModal(); resolve(true); }); cancelButton.addEventListener('click', () => { closeModal(); resolve(false); }); modalButtons.appendChild(confirmButton); modalButtons.appendChild(cancelButton); modalDialog.appendChild(modalMessage); modalDialog.appendChild(modalButtons); modalOverlay.appendChild(modalDialog); document.body.appendChild(modalOverlay); }); } export function show_message(msg) { app.ui.dialog.show(msg); app.ui.dialog.element.style.zIndex = 1100; } export async function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } export async function customConfirm(message) { try { let res = await window['app'].extensionManager.dialog .confirm({ title: 'Confirm', message: message }); return res; } catch { let res = await internalCustomConfirm(message); return res; } } export function customAlert(message) { try { window['app'].extensionManager.toast.addAlert(message); } catch { alert(message); } } export async function customPrompt(title, message) { try { let res = await window['app'].extensionManager.dialog .prompt({ title: title, message: message }); return res; } catch { return prompt(title, message) } } export function rebootAPI() { if ('electronAPI' in window) { window.electronAPI.restartApp(); return true; } customConfirm("Are you sure you'd like to reboot the server?").then((isConfirmed) => { if (isConfirmed) { try { api.fetchApi("/manager/reboot"); } catch(exception) {} } }); return false; } export async function migrateAPI() { let confirmed = await customConfirm("When performing a migration, existing installed custom nodes will be renamed and the server will be restarted. Are you sure you want to apply this?\n\n(If you don't perform the migration, ComfyUI-Manager's start-up time will be longer each time due to re-checking during startup.)") if (confirmed) { try { await api.fetchApi("/manager/migrate_unmanaged_nodes"); api.fetchApi("/manager/reboot"); } catch(exception) { } return true; } return false; } export var manager_instance = null; export function setManagerInstance(obj) { manager_instance = obj; } export function showToast(message, duration = 3000) { const toast = $el("div.comfy-toast", {textContent: message}); document.body.appendChild(toast); setTimeout(() => { toast.classList.add("comfy-toast-fadeout"); setTimeout(() => toast.remove(), 500); }, duration); } function isValidURL(url) { if(url.includes('&')) return false; const http_pattern = /^(https?|ftp):\/\/[^\s$?#]+$/; const ssh_pattern = /^(.+@|ssh:\/\/).+:.+$/; return http_pattern.test(url) || ssh_pattern.test(url); } export async function install_pip(packages) { if(packages.includes('&')) app.ui.dialog.show(`Invalid PIP package enumeration: '${packages}'`); const res = await api.fetchApi("/customnode/install/pip", { method: "POST", body: packages, }); if(res.status == 403) { show_message('This action is not allowed with this security level configuration.'); return; } if(res.status == 200) { show_message(`PIP package installation is processed.
To apply the pip packages, please click the button in ComfyUI.`); const rebootButton = document.getElementById('cm-reboot-button3'); const self = this; rebootButton.addEventListener("click", rebootAPI); } else { show_message(`Failed to install '${packages}'
See terminal log.`); } } export async function install_via_git_url(url, manager_dialog) { if(!url) { return; } if(!isValidURL(url)) { show_message(`Invalid Git url '${url}'`); return; } show_message(`Wait...

Installing '${url}'`); const res = await api.fetchApi("/customnode/install/git_url", { method: "POST", body: url, }); if(res.status == 403) { show_message('This action is not allowed with this security level configuration.'); return; } if(res.status == 200) { show_message(`'${url}' is installed
To apply the installed custom node, please ComfyUI.`); const rebootButton = document.getElementById('cm-reboot-button4'); const self = this; rebootButton.addEventListener("click", function() { if(rebootAPI()) { manager_dialog.close(); } }); } else { show_message(`Failed to install '${url}'
See terminal log.`); } } export async function free_models(free_execution_cache) { try { let mode = ""; if(free_execution_cache) { mode = '{"unload_models": true, "free_memory": true}'; } else { mode = '{"unload_models": true}'; } let res = await api.fetchApi(`/free`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: mode }); if (res.status == 200) { if(free_execution_cache) { showToast("'Models' and 'Execution Cache' have been cleared.", 3000); } else { showToast("Models' have been unloaded.", 3000); } } else { showToast('Unloading of models failed. Installed ComfyUI may be an outdated version.', 5000); } } catch (error) { showToast('An error occurred while trying to unload models.', 5000); } } export function md5(inputString) { const hc = '0123456789abcdef'; const rh = n => {let j,s='';for(j=0;j<=3;j++) s+=hc.charAt((n>>(j*8+4))&0x0F)+hc.charAt((n>>(j*8))&0x0F);return s;} const ad = (x,y) => {let l=(x&0xFFFF)+(y&0xFFFF);let m=(x>>16)+(y>>16)+(l>>16);return (m<<16)|(l&0xFFFF);} const rl = (n,c) => (n<>>(32-c)); const cm = (q,a,b,x,s,t) => ad(rl(ad(ad(a,q),ad(x,t)),s),b); const ff = (a,b,c,d,x,s,t) => cm((b&c)|((~b)&d),a,b,x,s,t); const gg = (a,b,c,d,x,s,t) => cm((b&d)|(c&(~d)),a,b,x,s,t); const hh = (a,b,c,d,x,s,t) => cm(b^c^d,a,b,x,s,t); const ii = (a,b,c,d,x,s,t) => cm(c^(b|(~d)),a,b,x,s,t); const sb = x => { let i;const nblk=((x.length+8)>>6)+1;const blks=[];for(i=0;i>2]|=x.charCodeAt(i)<<((i%4)*8);} blks[i>>2]|=0x80<<((i%4)*8);blks[nblk*16-2]=x.length*8;return blks; } let i,x=sb(inputString),a=1732584193,b=-271733879,c=-1732584194,d=271733878,olda,oldb,oldc,oldd; for(i=0;i { err = e; }); if (!res) { return { status: 400, error: new Error("Unknown Error") } } const { status, statusText } = res; if (err) { return { status, error: err } } if (status !== 200) { return { status, error: new Error(statusText || "Unknown Error") } } const data = await res.json(); if (!data) { return { status, error: new Error(`Failed to load data: ${route}`) } } return { status, data } } export const icons = { search: '', extensions: '', conflicts: '', passed: '', download: '' } export function sanitizeHTML(str) { return str .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); }