mirror of
https://git.datalinker.icu/ltdrdata/ComfyUI-Manager
synced 2025-12-08 21:54:26 +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
|
||||
|
||||
|
||||
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 '')
|
||||
|
||||
|
||||
|
||||
@ -18,6 +18,8 @@ import manager_core as core
|
||||
import manager_util
|
||||
import cm_global
|
||||
import logging
|
||||
import asyncio
|
||||
import queue
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
def handle_stream(stream, prefix):
|
||||
stream.reconfigure(encoding=locale.getpreferredencoding(), errors='replace')
|
||||
for msg in stream:
|
||||
@ -368,6 +369,147 @@ def nickname_filter(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")
|
||||
async def fetch_customnode_mappings(request):
|
||||
"""
|
||||
@ -870,7 +1012,24 @@ async def reinstall_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):
|
||||
if not is_allowed_security_level('middle'):
|
||||
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||
@ -913,26 +1072,23 @@ async def install_custom_node(request):
|
||||
logging.error(SECURITY_MESSAGE_GENERAL)
|
||||
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=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.")
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@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):
|
||||
if not is_allowed_security_level('middle'):
|
||||
logging.error(SECURITY_MESSAGE_GENERAL)
|
||||
@ -948,16 +1104,10 @@ async def fix_custom_node(request):
|
||||
# unknown
|
||||
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:
|
||||
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}'.")
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@routes.post("/customnode/install/git_url")
|
||||
@ -992,7 +1142,7 @@ async def install_custom_node_pip(request):
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@routes.post("/customnode/uninstall")
|
||||
@routes.post("/customnode/queue/uninstall")
|
||||
async def uninstall_custom_node(request):
|
||||
if not is_allowed_security_level('middle'):
|
||||
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||
@ -1009,17 +1159,13 @@ async def uninstall_custom_node(request):
|
||||
is_unknown = True
|
||||
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:
|
||||
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}'.")
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@routes.post("/customnode/update")
|
||||
@routes.post("/customnode/queue/update")
|
||||
async def update_custom_node(request):
|
||||
if not is_allowed_security_level('middle'):
|
||||
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||
@ -1034,16 +1180,10 @@ async def update_custom_node(request):
|
||||
# unknown
|
||||
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()
|
||||
|
||||
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}'.")
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@routes.get("/comfyui_manager/update_comfyui")
|
||||
@ -1092,7 +1232,7 @@ async def comfyui_switch_version(request):
|
||||
return web.Response(status=400)
|
||||
|
||||
|
||||
@routes.post("/customnode/disable")
|
||||
@routes.post("/customnode/queue/disable")
|
||||
async def disable_node(request):
|
||||
json_data = await request.json()
|
||||
|
||||
@ -1105,12 +1245,10 @@ async def disable_node(request):
|
||||
is_unknown = True
|
||||
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.json_response({}, content_type='application/json')
|
||||
|
||||
return web.Response(status=400, text="Failed to disable")
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@routes.get("/manager/migrate_unmanaged_nodes")
|
||||
@ -1149,37 +1287,44 @@ async def install_model(request):
|
||||
logging.error(SECURITY_MESSAGE_NORMAL_MINUS)
|
||||
return web.Response(status=403)
|
||||
|
||||
res = False
|
||||
def do_install():
|
||||
res = False
|
||||
|
||||
try:
|
||||
if model_path is not None:
|
||||
try:
|
||||
if model_path is not None:
|
||||
|
||||
model_url = json_data['url']
|
||||
logging.info(f"Install model '{json_data['name']}' from '{model_url}' into '{model_path}'")
|
||||
if not core.get_config()['model_download_by_agent'] and (
|
||||
model_url.startswith('https://github.com') or model_url.startswith('https://huggingface.co') or model_url.startswith('https://heibox.uni-heidelberg.de')):
|
||||
model_dir = get_model_dir(json_data, True)
|
||||
download_url(model_url, model_dir, filename=json_data['filename'])
|
||||
if model_path.endswith('.zip'):
|
||||
res = core.unzip(model_path)
|
||||
model_url = json_data['url']
|
||||
logging.info(f"Install model '{json_data['name']}' from '{model_url}' into '{model_path}'")
|
||||
if not core.get_config()['model_download_by_agent'] and (
|
||||
model_url.startswith('https://github.com') or model_url.startswith('https://huggingface.co') or model_url.startswith('https://heibox.uni-heidelberg.de')):
|
||||
model_dir = get_model_dir(json_data, True)
|
||||
download_url(model_url, model_dir, filename=json_data['filename'])
|
||||
if model_path.endswith('.zip'):
|
||||
res = core.unzip(model_path)
|
||||
else:
|
||||
res = True
|
||||
|
||||
if res:
|
||||
return web.json_response({}, content_type='application/json')
|
||||
else:
|
||||
res = True
|
||||
|
||||
if res:
|
||||
return web.json_response({}, content_type='application/json')
|
||||
res = download_url_with_agent(model_url, model_path)
|
||||
if res and model_path.endswith('.zip'):
|
||||
res = core.unzip(model_path)
|
||||
else:
|
||||
res = download_url_with_agent(model_url, model_path)
|
||||
if res and model_path.endswith('.zip'):
|
||||
res = core.unzip(model_path)
|
||||
else:
|
||||
logging.error(f"Model installation error: invalid model type - {json_data['type']}")
|
||||
logging.error(f"Model installation error: invalid model type - {json_data['type']}")
|
||||
|
||||
if res:
|
||||
return web.json_response({}, content_type='application/json')
|
||||
except Exception as e:
|
||||
logging.error(f"[ERROR] {e}", file=sys.stderr)
|
||||
if res:
|
||||
return web.json_response({}, content_type='application/json')
|
||||
except Exception as e:
|
||||
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")
|
||||
@ -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)
|
||||
|
||||
import asyncio
|
||||
|
||||
|
||||
async def default_cache_update():
|
||||
async def get_cache(filename):
|
||||
|
||||
@ -17,7 +17,6 @@ import {
|
||||
import { ComponentBuilderDialog, getPureName, load_components, set_component_policy } from "./components-manager.js";
|
||||
import { CustomNodesManager } from "./custom-nodes-manager.js";
|
||||
import { ModelManager } from "./model-manager.js";
|
||||
import { set_double_click_policy } from "./node_fixer.js";
|
||||
import { SnapshotManager } from "./snapshot.js";
|
||||
|
||||
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) {
|
||||
try {
|
||||
|
||||
@ -4,7 +4,7 @@ import { api } from "../../scripts/api.js";
|
||||
|
||||
import {
|
||||
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";
|
||||
|
||||
// https://cenfun.github.io/turbogrid/api.html
|
||||
@ -391,6 +391,8 @@ export class CustomNodesManager {
|
||||
this.restartMap = {};
|
||||
|
||||
this.init();
|
||||
|
||||
api.addEventListener("cm-install-status", this.onInstallStatus);
|
||||
}
|
||||
|
||||
init() {
|
||||
@ -1204,7 +1206,7 @@ export class CustomNodesManager {
|
||||
}
|
||||
|
||||
focusInstall(item, mode) {
|
||||
const cellNode = this.grid.getCellNode(item, "installed");
|
||||
const cellNode = this.grid.getCellNode(item, "action");
|
||||
if (cellNode) {
|
||||
const cellBtn = cellNode.querySelector(`button[mode="${mode}"]`);
|
||||
if (cellBtn) {
|
||||
@ -1269,6 +1271,13 @@ export class CustomNodesManager {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if(mode === "uninstall") {
|
||||
@ -1294,8 +1303,13 @@ export class CustomNodesManager {
|
||||
|
||||
let needRestart = false;
|
||||
let errorMsg = "";
|
||||
|
||||
await api.fetchApi('/customnode/queue/reset');
|
||||
this.install_context = btn;
|
||||
|
||||
for (const hash of list) {
|
||||
const item = this.grid.getRowItemBy("hash", hash);
|
||||
|
||||
if (!item) {
|
||||
errorMsg = `Not found custom node: ${hash}`;
|
||||
break;
|
||||
@ -1315,6 +1329,7 @@ export class CustomNodesManager {
|
||||
data.selected_version = selected_version;
|
||||
data.channel = this.channel;
|
||||
data.mode = this.mode;
|
||||
data.ui_id = hash;
|
||||
|
||||
let install_mode = mode;
|
||||
if(mode == 'switch') {
|
||||
@ -1332,14 +1347,14 @@ export class CustomNodesManager {
|
||||
api_mode = 'reinstall';
|
||||
}
|
||||
|
||||
const res = await api.fetchApi(`/customnode/${api_mode}`, {
|
||||
const res = await api.fetchApi(`/customnode/queue/${api_mode}`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
if (res.status != 200) {
|
||||
|
||||
errorMsg = `${item.title} ${mode} failed: `;
|
||||
|
||||
if(res.status == 403) {
|
||||
errorMsg += `This action is not allowed with this security level configuration.`;
|
||||
} else if(res.status == 404) {
|
||||
@ -1350,32 +1365,69 @@ export class CustomNodesManager {
|
||||
|
||||
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);
|
||||
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 {
|
||||
this.showStatus(`${label} ${list.length} custom node(s) successfully`);
|
||||
self.showStatus(`${label} ${result.length} custom node(s) successfully`);
|
||||
}
|
||||
|
||||
if (needRestart) {
|
||||
this.showRestart();
|
||||
this.showMessage(`To apply the installed/updated/disabled/enabled custom node, please restart ComfyUI. And refresh browser.`, "red")
|
||||
}
|
||||
self.showRestart();
|
||||
self.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 { 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) {
|
||||
const getOpts = nodeType.prototype.getExtraMenuOptions;
|
||||
nodeType.prototype.getExtraMenuOptions = function () {
|
||||
@ -153,62 +143,6 @@ function node_info_copy(src, dest, connect_both, copy_shape) {
|
||||
|
||||
app.registerExtension({
|
||||
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) {
|
||||
addMenuHandler(nodeType, function (_, options) {
|
||||
options.push({
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
[project]
|
||||
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."
|
||||
version = "3.11.3"
|
||||
version = "3.12"
|
||||
license = { file = "LICENSE.txt" }
|
||||
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