mirror of
https://git.datalinker.icu/ltdrdata/ComfyUI-Manager
synced 2025-12-09 06:04:31 +08:00
feat: custom-nodes-manager - background tasks(install/update/fix/disable/enable)
This commit is contained in:
parent
0f7b9d02a0
commit
4760deaf9c
@ -41,7 +41,7 @@ import manager_downloader
|
|||||||
from node_package import InstalledNodePackage
|
from node_package import InstalledNodePackage
|
||||||
|
|
||||||
|
|
||||||
version_code = [3, 11, 3]
|
version_code = [3, 12]
|
||||||
version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
|
version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,8 @@ import manager_core as core
|
|||||||
import manager_util
|
import manager_util
|
||||||
import cm_global
|
import cm_global
|
||||||
import logging
|
import logging
|
||||||
|
import asyncio
|
||||||
|
import queue
|
||||||
|
|
||||||
|
|
||||||
logging.info(f"### Loading: ComfyUI-Manager ({core.version_str})")
|
logging.info(f"### Loading: ComfyUI-Manager ({core.version_str})")
|
||||||
@ -31,7 +33,6 @@ SECURITY_MESSAGE_GENERAL = "ERROR: This installation is not allowed in this secu
|
|||||||
|
|
||||||
routes = PromptServer.instance.routes
|
routes = PromptServer.instance.routes
|
||||||
|
|
||||||
|
|
||||||
def handle_stream(stream, prefix):
|
def handle_stream(stream, prefix):
|
||||||
stream.reconfigure(encoding=locale.getpreferredencoding(), errors='replace')
|
stream.reconfigure(encoding=locale.getpreferredencoding(), errors='replace')
|
||||||
for msg in stream:
|
for msg in stream:
|
||||||
@ -368,6 +369,147 @@ def nickname_filter(json_obj):
|
|||||||
return json_obj
|
return json_obj
|
||||||
|
|
||||||
|
|
||||||
|
install_queue = queue.Queue()
|
||||||
|
install_result = {}
|
||||||
|
|
||||||
|
async def install_worker():
|
||||||
|
global install_result
|
||||||
|
global install_queue
|
||||||
|
|
||||||
|
async def do_install(item):
|
||||||
|
ui_id, node_spec_str, channel, mode, skip_post_install = item
|
||||||
|
|
||||||
|
try:
|
||||||
|
node_spec = core.unified_manager.resolve_node_spec(node_spec_str)
|
||||||
|
|
||||||
|
if node_spec is None:
|
||||||
|
logging.error(f"Cannot resolve install target: '{node_spec_str}'")
|
||||||
|
install_result[ui_id] = f"Cannot resolve install target: '{node_spec_str}'"
|
||||||
|
return
|
||||||
|
|
||||||
|
node_name, version_spec, is_specified = node_spec
|
||||||
|
res = await core.unified_manager.install_by_id(node_name, version_spec, channel, mode, return_postinstall=skip_post_install)
|
||||||
|
# discard post install if skip_post_install mode
|
||||||
|
|
||||||
|
if res.action not in ['skip', 'enable', 'install-git', 'install-cnr', 'switch-cnr']:
|
||||||
|
logging.error(f"[ComfyUI-Manager] Installation failed:\n{res.msg}")
|
||||||
|
install_result[ui_id] = res.msg
|
||||||
|
return
|
||||||
|
|
||||||
|
elif not res.result:
|
||||||
|
logging.error(f"[ComfyUI-Manager] Installation failed:\n{res.msg}")
|
||||||
|
install_result[ui_id] = res.msg
|
||||||
|
return
|
||||||
|
|
||||||
|
install_result[ui_id] = 'success'
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
install_result[ui_id] = f"Installation failed:\n{node_spec_str}"
|
||||||
|
|
||||||
|
async def do_update(item):
|
||||||
|
ui_id, node_name, node_ver = item
|
||||||
|
|
||||||
|
try:
|
||||||
|
res = core.unified_manager.unified_update(node_name, node_ver)
|
||||||
|
|
||||||
|
manager_util.clear_pip_cache()
|
||||||
|
|
||||||
|
if res.result:
|
||||||
|
install_result[ui_id] = 'success'
|
||||||
|
return
|
||||||
|
|
||||||
|
logging.error(f"\nERROR: An error occurred while updating '{node_name}'.")
|
||||||
|
install_result[ui_id] = f"An error occurred while updating '{node_name}'."
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
install_result[ui_id] = f"An error occurred while updating '{node_name}'."
|
||||||
|
|
||||||
|
async def do_fix(item):
|
||||||
|
ui_id, node_name, node_ver = item
|
||||||
|
|
||||||
|
try:
|
||||||
|
res = core.unified_manager.unified_fix(node_name, node_ver)
|
||||||
|
|
||||||
|
if res.result:
|
||||||
|
install_result[ui_id] = 'success'
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
logging.error(res.msg)
|
||||||
|
|
||||||
|
logging.error(f"\nERROR: An error occurred while fixing '{node_name}@{node_ver}'.")
|
||||||
|
install_result[ui_id] = f"An error occurred while fixing '{node_name}@{node_ver}'."
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
install_result[ui_id] = f"An error occurred while fixing '{node_name}@{node_ver}'."
|
||||||
|
|
||||||
|
async def do_uninstall(item):
|
||||||
|
ui_id, node_name, is_unknown = item
|
||||||
|
|
||||||
|
try:
|
||||||
|
res = core.unified_manager.unified_uninstall(node_name, is_unknown)
|
||||||
|
|
||||||
|
if res.result:
|
||||||
|
install_result[ui_id] = 'success'
|
||||||
|
return
|
||||||
|
|
||||||
|
logging.error(f"\nERROR: An error occurred while uninstalling '{node_name}'.")
|
||||||
|
install_result[ui_id] = f"An error occurred while uninstalling '{node_name}'."
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
install_result[ui_id] = f"An error occurred while uninstalling '{node_name}'."
|
||||||
|
|
||||||
|
async def do_disable(item):
|
||||||
|
ui_id, node_name, is_unknown = item
|
||||||
|
|
||||||
|
try:
|
||||||
|
res = core.unified_manager.unified_disable(node_name, is_unknown)
|
||||||
|
|
||||||
|
if res:
|
||||||
|
install_result[ui_id] = 'success'
|
||||||
|
return
|
||||||
|
|
||||||
|
install_result[ui_id] = f"Failed to disable: '{node_name}'"
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
install_result[ui_id] = f"Failed to disable: '{node_name}'"
|
||||||
|
|
||||||
|
stats = {}
|
||||||
|
|
||||||
|
while True:
|
||||||
|
done_count = len(install_result)
|
||||||
|
total_count = done_count + install_queue.qsize()
|
||||||
|
|
||||||
|
if install_queue.empty():
|
||||||
|
logging.info(f"\n[ComfyUI-Manager] Queued works are completed.\n{stats}")
|
||||||
|
|
||||||
|
logging.info("\nAfter restarting ComfyUI, please refresh the browser.")
|
||||||
|
PromptServer.instance.send_sync("cm-install-status",
|
||||||
|
{'status': 'done', 'result': install_result,
|
||||||
|
'total_count': total_count, 'done_count': done_count})
|
||||||
|
install_result = {}
|
||||||
|
install_queue = queue.Queue()
|
||||||
|
return
|
||||||
|
|
||||||
|
kind, item = install_queue.get()
|
||||||
|
|
||||||
|
if kind == 'install':
|
||||||
|
await do_install(item)
|
||||||
|
elif kind == 'update':
|
||||||
|
await do_update(item)
|
||||||
|
elif kind == 'fix':
|
||||||
|
await do_fix(item)
|
||||||
|
elif kind == 'uninstall':
|
||||||
|
await do_uninstall(item)
|
||||||
|
elif kind == 'disable':
|
||||||
|
await do_disable(item)
|
||||||
|
|
||||||
|
stats[kind] = stats.get(kind, 0) + 1
|
||||||
|
|
||||||
|
PromptServer.instance.send_sync("cm-install-status",
|
||||||
|
{'status': 'in_progress', 'target': item[0],
|
||||||
|
'total_count': total_count, 'done_count': done_count})
|
||||||
|
|
||||||
|
|
||||||
@routes.get("/customnode/getmappings")
|
@routes.get("/customnode/getmappings")
|
||||||
async def fetch_customnode_mappings(request):
|
async def fetch_customnode_mappings(request):
|
||||||
"""
|
"""
|
||||||
@ -870,7 +1012,24 @@ async def reinstall_custom_node(request):
|
|||||||
await install_custom_node(request)
|
await install_custom_node(request)
|
||||||
|
|
||||||
|
|
||||||
@routes.post("/customnode/install")
|
@routes.get("/customnode/queue/reset")
|
||||||
|
async def reset_queue(request):
|
||||||
|
global install_queue
|
||||||
|
install_queue = queue.Queue()
|
||||||
|
return web.Response(status=200)
|
||||||
|
|
||||||
|
|
||||||
|
@routes.get("/customnode/queue/count")
|
||||||
|
async def reset_queue(request):
|
||||||
|
global install_queue
|
||||||
|
|
||||||
|
done_count = len(install_result)
|
||||||
|
total_count = done_count + install_queue.qsize()
|
||||||
|
|
||||||
|
return web.json_response({'total_count': total_count, 'done_count': done_count})
|
||||||
|
|
||||||
|
|
||||||
|
@routes.post("/customnode/queue/install")
|
||||||
async def install_custom_node(request):
|
async def install_custom_node(request):
|
||||||
if not is_allowed_security_level('middle'):
|
if not is_allowed_security_level('middle'):
|
||||||
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||||
@ -913,26 +1072,23 @@ async def install_custom_node(request):
|
|||||||
logging.error(SECURITY_MESSAGE_GENERAL)
|
logging.error(SECURITY_MESSAGE_GENERAL)
|
||||||
return web.Response(status=404, text="A security error has occurred. Please check the terminal logs")
|
return web.Response(status=404, text="A security error has occurred. Please check the terminal logs")
|
||||||
|
|
||||||
node_spec = core.unified_manager.resolve_node_spec(node_spec_str)
|
install_item = json_data.get('ui_id'), node_spec_str, json_data['channel'], json_data['mode'], skip_post_install
|
||||||
|
install_queue.put(("install", install_item))
|
||||||
|
|
||||||
if node_spec is None:
|
return web.Response(status=200)
|
||||||
return web.Response(status=400, text=f"Cannot resolve install target: '{node_spec_str}'")
|
|
||||||
|
|
||||||
node_name, version_spec, is_specified = node_spec
|
|
||||||
res = await core.unified_manager.install_by_id(node_name, version_spec, json_data['channel'], json_data['mode'], return_postinstall=skip_post_install)
|
|
||||||
# discard post install if skip_post_install mode
|
|
||||||
|
|
||||||
if res.action not in ['skip', 'enable', 'install-git', 'install-cnr', 'switch-cnr']:
|
|
||||||
logging.error(f"[ComfyUI-Manager] Installation failed:\n{res.msg}")
|
|
||||||
return web.Response(status=400, text=res.msg)
|
|
||||||
elif not res.result:
|
|
||||||
logging.error(f"[ComfyUI-Manager] Installation failed:\n{res.msg}")
|
|
||||||
return web.Response(status=400, text=res.msg)
|
|
||||||
|
|
||||||
return web.Response(status=200, text="Installation success.")
|
|
||||||
|
|
||||||
|
|
||||||
@routes.post("/customnode/fix")
|
@routes.get("/customnode/queue/start")
|
||||||
|
async def queue_start(request):
|
||||||
|
global install_result
|
||||||
|
install_result = {}
|
||||||
|
|
||||||
|
threading.Thread(target=lambda: asyncio.run(install_worker())).start()
|
||||||
|
|
||||||
|
return web.Response(status=200)
|
||||||
|
|
||||||
|
|
||||||
|
@routes.post("/customnode/queue/fix")
|
||||||
async def fix_custom_node(request):
|
async def fix_custom_node(request):
|
||||||
if not is_allowed_security_level('middle'):
|
if not is_allowed_security_level('middle'):
|
||||||
logging.error(SECURITY_MESSAGE_GENERAL)
|
logging.error(SECURITY_MESSAGE_GENERAL)
|
||||||
@ -948,16 +1104,10 @@ async def fix_custom_node(request):
|
|||||||
# unknown
|
# unknown
|
||||||
node_name = os.path.basename(json_data['files'][0])
|
node_name = os.path.basename(json_data['files'][0])
|
||||||
|
|
||||||
res = core.unified_manager.unified_fix(node_name, node_ver)
|
update_item = json_data.get('ui_id'), node_name, json_data['version']
|
||||||
|
install_queue.put(("fix", update_item))
|
||||||
|
|
||||||
if res.result:
|
return web.Response(status=200)
|
||||||
logging.info("\nAfter restarting ComfyUI, please refresh the browser.")
|
|
||||||
return web.json_response({}, content_type='application/json')
|
|
||||||
else:
|
|
||||||
logging.error(res.msg)
|
|
||||||
|
|
||||||
logging.error(f"\nERROR: An error occurred while fixing '{node_name}@{node_ver}'.")
|
|
||||||
return web.Response(status=400, text=f"An error occurred while fixing '{node_name}@{node_ver}'.")
|
|
||||||
|
|
||||||
|
|
||||||
@routes.post("/customnode/install/git_url")
|
@routes.post("/customnode/install/git_url")
|
||||||
@ -992,7 +1142,7 @@ async def install_custom_node_pip(request):
|
|||||||
return web.Response(status=200)
|
return web.Response(status=200)
|
||||||
|
|
||||||
|
|
||||||
@routes.post("/customnode/uninstall")
|
@routes.post("/customnode/queue/uninstall")
|
||||||
async def uninstall_custom_node(request):
|
async def uninstall_custom_node(request):
|
||||||
if not is_allowed_security_level('middle'):
|
if not is_allowed_security_level('middle'):
|
||||||
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||||
@ -1009,17 +1159,13 @@ async def uninstall_custom_node(request):
|
|||||||
is_unknown = True
|
is_unknown = True
|
||||||
node_name = os.path.basename(json_data['files'][0])
|
node_name = os.path.basename(json_data['files'][0])
|
||||||
|
|
||||||
res = core.unified_manager.unified_uninstall(node_name, is_unknown)
|
uninstall_item = json_data.get('ui_id'), node_name, is_unknown
|
||||||
|
install_queue.put(("uninstall", uninstall_item))
|
||||||
|
|
||||||
if res.result:
|
return web.Response(status=200)
|
||||||
logging.info("\nAfter restarting ComfyUI, please refresh the browser.")
|
|
||||||
return web.json_response({}, content_type='application/json')
|
|
||||||
|
|
||||||
logging.error(f"\nERROR: An error occurred while uninstalling '{node_name}'.")
|
|
||||||
return web.Response(status=400, text=f"An error occurred while uninstalling '{node_name}'.")
|
|
||||||
|
|
||||||
|
|
||||||
@routes.post("/customnode/update")
|
@routes.post("/customnode/queue/update")
|
||||||
async def update_custom_node(request):
|
async def update_custom_node(request):
|
||||||
if not is_allowed_security_level('middle'):
|
if not is_allowed_security_level('middle'):
|
||||||
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||||
@ -1034,16 +1180,10 @@ async def update_custom_node(request):
|
|||||||
# unknown
|
# unknown
|
||||||
node_name = os.path.basename(json_data['files'][0])
|
node_name = os.path.basename(json_data['files'][0])
|
||||||
|
|
||||||
res = core.unified_manager.unified_update(node_name, json_data['version'])
|
update_item = json_data.get('ui_id'), node_name, json_data['version']
|
||||||
|
install_queue.put(("update", update_item))
|
||||||
|
|
||||||
manager_util.clear_pip_cache()
|
return web.Response(status=200)
|
||||||
|
|
||||||
if res.result:
|
|
||||||
logging.info("\nAfter restarting ComfyUI, please refresh the browser.")
|
|
||||||
return web.json_response({}, content_type='application/json')
|
|
||||||
|
|
||||||
logging.error(f"\nERROR: An error occurred while updating '{node_name}'.")
|
|
||||||
return web.Response(status=400, text=f"An error occurred while updating '{node_name}'.")
|
|
||||||
|
|
||||||
|
|
||||||
@routes.get("/comfyui_manager/update_comfyui")
|
@routes.get("/comfyui_manager/update_comfyui")
|
||||||
@ -1092,7 +1232,7 @@ async def comfyui_switch_version(request):
|
|||||||
return web.Response(status=400)
|
return web.Response(status=400)
|
||||||
|
|
||||||
|
|
||||||
@routes.post("/customnode/disable")
|
@routes.post("/customnode/queue/disable")
|
||||||
async def disable_node(request):
|
async def disable_node(request):
|
||||||
json_data = await request.json()
|
json_data = await request.json()
|
||||||
|
|
||||||
@ -1105,12 +1245,10 @@ async def disable_node(request):
|
|||||||
is_unknown = True
|
is_unknown = True
|
||||||
node_name = os.path.basename(json_data['files'][0])
|
node_name = os.path.basename(json_data['files'][0])
|
||||||
|
|
||||||
res = core.unified_manager.unified_disable(node_name, is_unknown)
|
update_item = json_data.get('ui_id'), node_name, is_unknown
|
||||||
|
install_queue.put(("disable", update_item))
|
||||||
|
|
||||||
if res:
|
return web.Response(status=200)
|
||||||
return web.json_response({}, content_type='application/json')
|
|
||||||
|
|
||||||
return web.Response(status=400, text="Failed to disable")
|
|
||||||
|
|
||||||
|
|
||||||
@routes.get("/manager/migrate_unmanaged_nodes")
|
@routes.get("/manager/migrate_unmanaged_nodes")
|
||||||
@ -1149,6 +1287,7 @@ async def install_model(request):
|
|||||||
logging.error(SECURITY_MESSAGE_NORMAL_MINUS)
|
logging.error(SECURITY_MESSAGE_NORMAL_MINUS)
|
||||||
return web.Response(status=403)
|
return web.Response(status=403)
|
||||||
|
|
||||||
|
def do_install():
|
||||||
res = False
|
res = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -1178,9 +1317,15 @@ async def install_model(request):
|
|||||||
return web.json_response({}, content_type='application/json')
|
return web.json_response({}, content_type='application/json')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"[ERROR] {e}", file=sys.stderr)
|
logging.error(f"[ERROR] {e}", file=sys.stderr)
|
||||||
|
|
||||||
return web.Response(status=400)
|
return web.Response(status=400)
|
||||||
|
|
||||||
|
# Run the installation in a thread pool
|
||||||
|
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||||||
|
|
||||||
|
asyncio.get_event_loop().run_in_executor(executor, do_install)
|
||||||
|
|
||||||
|
return web.Response(status=200)
|
||||||
|
|
||||||
|
|
||||||
@routes.get("/manager/preview_method")
|
@routes.get("/manager/preview_method")
|
||||||
async def preview_method(request):
|
async def preview_method(request):
|
||||||
@ -1408,8 +1553,6 @@ def confirm_try_install(sender, custom_node_url, msg):
|
|||||||
|
|
||||||
cm_global.register_api('cm.try-install-custom-node', confirm_try_install)
|
cm_global.register_api('cm.try-install-custom-node', confirm_try_install)
|
||||||
|
|
||||||
import asyncio
|
|
||||||
|
|
||||||
|
|
||||||
async def default_cache_update():
|
async def default_cache_update():
|
||||||
async def get_cache(filename):
|
async def get_cache(filename):
|
||||||
|
|||||||
@ -17,7 +17,6 @@ import {
|
|||||||
import { ComponentBuilderDialog, getPureName, load_components, set_component_policy } from "./components-manager.js";
|
import { ComponentBuilderDialog, getPureName, load_components, set_component_policy } from "./components-manager.js";
|
||||||
import { CustomNodesManager } from "./custom-nodes-manager.js";
|
import { CustomNodesManager } from "./custom-nodes-manager.js";
|
||||||
import { ModelManager } from "./model-manager.js";
|
import { ModelManager } from "./model-manager.js";
|
||||||
import { set_double_click_policy } from "./node_fixer.js";
|
|
||||||
import { SnapshotManager } from "./snapshot.js";
|
import { SnapshotManager } from "./snapshot.js";
|
||||||
|
|
||||||
var docStyle = document.createElement('style');
|
var docStyle = document.createElement('style');
|
||||||
|
|||||||
14
js/common.js
14
js/common.js
@ -130,6 +130,20 @@ export function customAlert(message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function infoToast(summary, message) {
|
||||||
|
try {
|
||||||
|
app.extensionManager.toast.add({
|
||||||
|
severity: 'info',
|
||||||
|
summary: summary,
|
||||||
|
detail: message,
|
||||||
|
life: 3000
|
||||||
|
})
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export async function customPrompt(title, message) {
|
export async function customPrompt(title, message) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { api } from "../../scripts/api.js";
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
manager_instance, rebootAPI, install_via_git_url,
|
manager_instance, rebootAPI, install_via_git_url,
|
||||||
fetchData, md5, icons, show_message, customConfirm, customAlert, customPrompt, sanitizeHTML
|
fetchData, md5, icons, show_message, customConfirm, customAlert, customPrompt, sanitizeHTML, infoToast
|
||||||
} from "./common.js";
|
} from "./common.js";
|
||||||
|
|
||||||
// https://cenfun.github.io/turbogrid/api.html
|
// https://cenfun.github.io/turbogrid/api.html
|
||||||
@ -391,6 +391,8 @@ export class CustomNodesManager {
|
|||||||
this.restartMap = {};
|
this.restartMap = {};
|
||||||
|
|
||||||
this.init();
|
this.init();
|
||||||
|
|
||||||
|
api.addEventListener("cm-install-status", this.onInstallStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
@ -1204,7 +1206,7 @@ export class CustomNodesManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
focusInstall(item, mode) {
|
focusInstall(item, mode) {
|
||||||
const cellNode = this.grid.getCellNode(item, "installed");
|
const cellNode = this.grid.getCellNode(item, "action");
|
||||||
if (cellNode) {
|
if (cellNode) {
|
||||||
const cellBtn = cellNode.querySelector(`button[mode="${mode}"]`);
|
const cellBtn = cellNode.querySelector(`button[mode="${mode}"]`);
|
||||||
if (cellBtn) {
|
if (cellBtn) {
|
||||||
@ -1269,6 +1271,13 @@ export class CustomNodesManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async installNodes(list, btn, title, selected_version) {
|
async installNodes(list, btn, title, selected_version) {
|
||||||
|
let stats = await api.fetchApi('/customnode/queue/count');
|
||||||
|
stats = await stats.json();
|
||||||
|
if(stats.total_count > 0) {
|
||||||
|
customAlert(`[ComfyUI-Manager] There are already tasks in progress. Please try again after it is completed. (${stats.done_count}/${stats.total_count})`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const { target, label, mode} = btn;
|
const { target, label, mode} = btn;
|
||||||
|
|
||||||
if(mode === "uninstall") {
|
if(mode === "uninstall") {
|
||||||
@ -1294,8 +1303,13 @@ export class CustomNodesManager {
|
|||||||
|
|
||||||
let needRestart = false;
|
let needRestart = false;
|
||||||
let errorMsg = "";
|
let errorMsg = "";
|
||||||
|
|
||||||
|
await api.fetchApi('/customnode/queue/reset');
|
||||||
|
this.install_context = btn;
|
||||||
|
|
||||||
for (const hash of list) {
|
for (const hash of list) {
|
||||||
const item = this.grid.getRowItemBy("hash", hash);
|
const item = this.grid.getRowItemBy("hash", hash);
|
||||||
|
|
||||||
if (!item) {
|
if (!item) {
|
||||||
errorMsg = `Not found custom node: ${hash}`;
|
errorMsg = `Not found custom node: ${hash}`;
|
||||||
break;
|
break;
|
||||||
@ -1315,6 +1329,7 @@ export class CustomNodesManager {
|
|||||||
data.selected_version = selected_version;
|
data.selected_version = selected_version;
|
||||||
data.channel = this.channel;
|
data.channel = this.channel;
|
||||||
data.mode = this.mode;
|
data.mode = this.mode;
|
||||||
|
data.ui_id = hash;
|
||||||
|
|
||||||
let install_mode = mode;
|
let install_mode = mode;
|
||||||
if(mode == 'switch') {
|
if(mode == 'switch') {
|
||||||
@ -1332,14 +1347,14 @@ export class CustomNodesManager {
|
|||||||
api_mode = 'reinstall';
|
api_mode = 'reinstall';
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await api.fetchApi(`/customnode/${api_mode}`, {
|
const res = await api.fetchApi(`/customnode/queue/${api_mode}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(data)
|
body: JSON.stringify(data)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status != 200) {
|
if (res.status != 200) {
|
||||||
|
|
||||||
errorMsg = `${item.title} ${mode} failed: `;
|
errorMsg = `${item.title} ${mode} failed: `;
|
||||||
|
|
||||||
if(res.status == 403) {
|
if(res.status == 403) {
|
||||||
errorMsg += `This action is not allowed with this security level configuration.`;
|
errorMsg += `This action is not allowed with this security level configuration.`;
|
||||||
} else if(res.status == 404) {
|
} else if(res.status == 404) {
|
||||||
@ -1350,32 +1365,69 @@ export class CustomNodesManager {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
needRestart = true;
|
|
||||||
|
|
||||||
this.grid.setRowSelected(item, false);
|
|
||||||
item.restart = true;
|
|
||||||
this.restartMap[item.hash] = true;
|
|
||||||
this.grid.updateCell(item, "action");
|
|
||||||
|
|
||||||
//console.log(res.data);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
target.classList.remove("cn-btn-loading");
|
|
||||||
|
|
||||||
if(errorMsg) {
|
if(errorMsg) {
|
||||||
this.showError(errorMsg);
|
this.showError(errorMsg);
|
||||||
show_message("Installation Error:\n"+errorMsg);
|
show_message("Installation Error:\n"+errorMsg);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
await api.fetchApi('/customnode/queue/start');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async onInstallStatus(event) {
|
||||||
|
let self = CustomNodesManager.instance;
|
||||||
|
if(event.detail.status == 'in_progress') {
|
||||||
|
const hash = event.detail.target;
|
||||||
|
|
||||||
|
const item = self.grid.getRowItemBy("hash", hash);
|
||||||
|
|
||||||
|
item.restart = true;
|
||||||
|
self.restartMap[item.hash] = true;
|
||||||
|
self.grid.updateCell(item, "action");
|
||||||
|
}
|
||||||
|
else if(event.detail.status == 'done') {
|
||||||
|
self.onInstallCompleted(event.detail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async onInstallCompleted(info) {
|
||||||
|
let result = info.result;
|
||||||
|
|
||||||
|
let self = CustomNodesManager.instance;
|
||||||
|
|
||||||
|
if(!self.install_context) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { target, label, mode } = self.install_context;
|
||||||
|
target.classList.remove("cn-btn-loading");
|
||||||
|
|
||||||
|
let errorMsg = "";
|
||||||
|
|
||||||
|
for(let hash in result){
|
||||||
|
let v = result[hash];
|
||||||
|
|
||||||
|
const item = self.grid.getRowItemBy("hash", hash);
|
||||||
|
self.grid.setRowSelected(item, false);
|
||||||
|
|
||||||
|
if(v != 'success')
|
||||||
|
errorMsg += v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorMsg) {
|
||||||
|
self.showError(errorMsg);
|
||||||
|
show_message("Installation Error:\n"+errorMsg);
|
||||||
} else {
|
} else {
|
||||||
this.showStatus(`${label} ${list.length} custom node(s) successfully`);
|
self.showStatus(`${label} ${result.length} custom node(s) successfully`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needRestart) {
|
self.showRestart();
|
||||||
this.showRestart();
|
self.showMessage(`To apply the installed/updated/disabled/enabled custom node, please restart ComfyUI. And refresh browser.`, "red");
|
||||||
this.showMessage(`To apply the installed/updated/disabled/enabled custom node, please restart ComfyUI. And refresh browser.`, "red")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
infoToast(`[ComfyUI-Manager] All tasks in the queue have been completed.\n${info.done_count}/${info.total_count}`);
|
||||||
|
self.install_context = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===========================================================================================
|
// ===========================================================================================
|
||||||
|
|||||||
@ -1,16 +1,6 @@
|
|||||||
import { app } from "../../scripts/app.js";
|
import { app } from "../../scripts/app.js";
|
||||||
import { api } from "../../scripts/api.js";
|
import { api } from "../../scripts/api.js";
|
||||||
|
|
||||||
let double_click_policy = "copy-all";
|
|
||||||
|
|
||||||
api.fetchApi('/manager/dbl_click/policy')
|
|
||||||
.then(response => response.text())
|
|
||||||
.then(data => set_double_click_policy(data));
|
|
||||||
|
|
||||||
export function set_double_click_policy(mode) {
|
|
||||||
double_click_policy = mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
function addMenuHandler(nodeType, cb) {
|
function addMenuHandler(nodeType, cb) {
|
||||||
const getOpts = nodeType.prototype.getExtraMenuOptions;
|
const getOpts = nodeType.prototype.getExtraMenuOptions;
|
||||||
nodeType.prototype.getExtraMenuOptions = function () {
|
nodeType.prototype.getExtraMenuOptions = function () {
|
||||||
@ -153,62 +143,6 @@ function node_info_copy(src, dest, connect_both, copy_shape) {
|
|||||||
|
|
||||||
app.registerExtension({
|
app.registerExtension({
|
||||||
name: "Comfy.Manager.NodeFixer",
|
name: "Comfy.Manager.NodeFixer",
|
||||||
|
|
||||||
async nodeCreated(node, app) {
|
|
||||||
let orig_dblClick = node.onDblClick;
|
|
||||||
node.onDblClick = function (e, pos, self) {
|
|
||||||
orig_dblClick?.apply?.(this, arguments);
|
|
||||||
|
|
||||||
if((!node.inputs && !node.outputs) || pos[1] > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch(double_click_policy) {
|
|
||||||
case "copy-all":
|
|
||||||
case "copy-full":
|
|
||||||
case "copy-input":
|
|
||||||
{
|
|
||||||
if(node.inputs?.some(x => x.link != null) || node.outputs?.some(x => x.links != null && x.links.length > 0) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
let src_node = lookup_nearest_nodes(node);
|
|
||||||
if(src_node)
|
|
||||||
{
|
|
||||||
let both_connection = double_click_policy != "copy-input";
|
|
||||||
let copy_shape = double_click_policy == "copy-full";
|
|
||||||
node_info_copy(src_node, node, both_connection, copy_shape);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "possible-input":
|
|
||||||
{
|
|
||||||
let nearest_inputs = lookup_nearest_inputs(node);
|
|
||||||
if(nearest_inputs)
|
|
||||||
connect_inputs(nearest_inputs, node);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "dual":
|
|
||||||
{
|
|
||||||
if(pos[0] < node.size[0]/2) {
|
|
||||||
// left: possible-input
|
|
||||||
let nearest_inputs = lookup_nearest_inputs(node);
|
|
||||||
if(nearest_inputs)
|
|
||||||
connect_inputs(nearest_inputs, node);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// right: copy-all
|
|
||||||
if(node.inputs?.some(x => x.link != null) || node.outputs?.some(x => x.links != null && x.links.length > 0) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
let src_node = lookup_nearest_nodes(node);
|
|
||||||
if(src_node)
|
|
||||||
node_info_copy(src_node, node, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
beforeRegisterNodeDef(nodeType, nodeData, app) {
|
beforeRegisterNodeDef(nodeType, nodeData, app) {
|
||||||
addMenuHandler(nodeType, function (_, options) {
|
addMenuHandler(nodeType, function (_, options) {
|
||||||
options.push({
|
options.push({
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "comfyui-manager"
|
name = "comfyui-manager"
|
||||||
description = "ComfyUI-Manager provides features to install and manage custom nodes for ComfyUI, as well as various functionalities to assist with ComfyUI."
|
description = "ComfyUI-Manager provides features to install and manage custom nodes for ComfyUI, as well as various functionalities to assist with ComfyUI."
|
||||||
version = "3.11.3"
|
version = "3.12"
|
||||||
license = { file = "LICENSE.txt" }
|
license = { file = "LICENSE.txt" }
|
||||||
dependencies = ["GitPython", "PyGithub", "matrix-client==0.4.0", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions"]
|
dependencies = ["GitPython", "PyGithub", "matrix-client==0.4.0", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions"]
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user