|
import { api } from "../../scripts/api.js"; |
|
import { app } from "../../scripts/app.js"; |
|
import { $el, ComfyDialog } from "../../scripts/ui.js"; |
|
import { |
|
SUPPORTED_OUTPUT_NODE_TYPES, |
|
ShareDialog, |
|
ShareDialogChooser, |
|
getPotentialOutputsAndOutputNodes, |
|
showOpenArtShareDialog, |
|
showShareDialog, |
|
showYouMLShareDialog |
|
} from "./comfyui-share-common.js"; |
|
import { OpenArtShareDialog } from "./comfyui-share-openart.js"; |
|
import { |
|
free_models, install_pip, install_via_git_url, manager_instance, |
|
rebootAPI, setManagerInstance, show_message, customAlert, customPrompt, |
|
infoToast, showTerminal, setNeedRestart |
|
} from "./common.js"; |
|
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 { SnapshotManager } from "./snapshot.js"; |
|
|
|
let manager_version = await getVersion(); |
|
|
|
var docStyle = document.createElement('style'); |
|
docStyle.innerHTML = ` |
|
.comfy-toast { |
|
position: fixed; |
|
bottom: 20px; |
|
left: 50%; |
|
transform: translateX(-50%); |
|
background-color: rgba(0, 0, 0, 0.7); |
|
color: white; |
|
padding: 10px 20px; |
|
border-radius: 5px; |
|
z-index: 1000; |
|
transition: opacity 0.5s; |
|
} |
|
|
|
.comfy-toast-fadeout { |
|
opacity: 0; |
|
} |
|
|
|
#cm-manager-dialog { |
|
width: 1000px; |
|
height: 455px; |
|
box-sizing: content-box; |
|
z-index: 1000; |
|
overflow-y: auto; |
|
} |
|
|
|
.cb-widget { |
|
width: 400px; |
|
height: 25px; |
|
box-sizing: border-box; |
|
z-index: 1000; |
|
margin-top: 10px; |
|
margin-bottom: 5px; |
|
} |
|
|
|
.cb-widget-input { |
|
width: 305px; |
|
height: 25px; |
|
box-sizing: border-box; |
|
} |
|
.cb-widget-input:disabled { |
|
background-color: #444444; |
|
color: white; |
|
} |
|
|
|
.cb-widget-input-label { |
|
width: 90px; |
|
height: 25px; |
|
box-sizing: border-box; |
|
color: white; |
|
text-align: right; |
|
display: inline-block; |
|
margin-right: 5px; |
|
} |
|
|
|
.cm-menu-container { |
|
column-gap: 20px; |
|
display: flex; |
|
flex-wrap: wrap; |
|
justify-content: center; |
|
box-sizing: content-box; |
|
} |
|
|
|
.cm-menu-column { |
|
display: flex; |
|
flex-direction: column; |
|
flex: 1 1 auto; |
|
width: 300px; |
|
box-sizing: content-box; |
|
} |
|
|
|
.cm-title { |
|
background-color: black; |
|
text-align: center; |
|
height: 40px; |
|
width: calc(100% - 10px); |
|
font-weight: bold; |
|
justify-content: center; |
|
align-content: center; |
|
vertical-align: middle; |
|
} |
|
|
|
#custom-nodes-grid a { |
|
color: #5555FF; |
|
font-weight: bold; |
|
text-decoration: none; |
|
} |
|
|
|
#custom-nodes-grid a:hover { |
|
color: #7777FF; |
|
text-decoration: underline; |
|
} |
|
|
|
#external-models-grid a { |
|
color: #5555FF; |
|
font-weight: bold; |
|
text-decoration: none; |
|
} |
|
|
|
#external-models-grid a:hover { |
|
color: #7777FF; |
|
text-decoration: underline; |
|
} |
|
|
|
#alternatives-grid a { |
|
color: #5555FF; |
|
font-weight: bold; |
|
text-decoration: none; |
|
} |
|
|
|
#alternatives-grid a:hover { |
|
color: #7777FF; |
|
text-decoration: underline; |
|
} |
|
|
|
.cm-notice-board { |
|
width: 290px; |
|
height: 230px; |
|
overflow: auto; |
|
color: var(--input-text); |
|
border: 1px solid var(--descrip-text); |
|
padding: 5px 10px; |
|
overflow-x: hidden; |
|
box-sizing: content-box; |
|
} |
|
|
|
.cm-notice-board > ul { |
|
display: block; |
|
list-style-type: disc; |
|
margin-block-start: 1em; |
|
margin-block-end: 1em; |
|
margin-inline-start: 0px; |
|
margin-inline-end: 0px; |
|
padding-inline-start: 40px; |
|
} |
|
|
|
.cm-conflicted-nodes-text { |
|
background-color: #CCCC55 !important; |
|
color: #AA3333 !important; |
|
font-size: 10px; |
|
border-radius: 5px; |
|
padding: 10px; |
|
} |
|
|
|
.cm-warn-note { |
|
background-color: #101010 !important; |
|
color: #FF3800 !important; |
|
font-size: 13px; |
|
border-radius: 5px; |
|
padding: 10px; |
|
overflow-x: hidden; |
|
overflow: auto; |
|
} |
|
|
|
.cm-info-note { |
|
background-color: #101010 !important; |
|
color: #FF3800 !important; |
|
font-size: 13px; |
|
border-radius: 5px; |
|
padding: 10px; |
|
overflow-x: hidden; |
|
overflow: auto; |
|
} |
|
`; |
|
|
|
function is_legacy_front() { |
|
let compareVersion = '1.2.49'; |
|
try { |
|
const frontendVersion = window['__COMFYUI_FRONTEND_VERSION__']; |
|
if (typeof frontendVersion !== 'string') { |
|
return false; |
|
} |
|
|
|
function parseVersion(versionString) { |
|
const parts = versionString.split('.').map(Number); |
|
return parts.length === 3 && parts.every(part => !isNaN(part)) ? parts : null; |
|
} |
|
|
|
const currentVersion = parseVersion(frontendVersion); |
|
const comparisonVersion = parseVersion(compareVersion); |
|
|
|
if (!currentVersion || !comparisonVersion) { |
|
return false; |
|
} |
|
|
|
for (let i = 0; i < 3; i++) { |
|
if (currentVersion[i] > comparisonVersion[i]) { |
|
return false; |
|
} else if (currentVersion[i] < comparisonVersion[i]) { |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} catch { |
|
return true; |
|
} |
|
} |
|
|
|
document.head.appendChild(docStyle); |
|
|
|
var update_comfyui_button = null; |
|
var switch_comfyui_button = null; |
|
var update_all_button = null; |
|
var restart_stop_button = null; |
|
var update_policy_combo = null; |
|
|
|
let share_option = 'all'; |
|
var is_updating = false; |
|
|
|
|
|
|
|
const style = ` |
|
#workflowgallery-button { |
|
width: 310px; |
|
height: 27px; |
|
padding: 0px !important; |
|
position: relative; |
|
overflow: hidden; |
|
font-size: 17px !important; |
|
} |
|
#cm-nodeinfo-button { |
|
width: 310px; |
|
height: 27px; |
|
padding: 0px !important; |
|
position: relative; |
|
overflow: hidden; |
|
font-size: 17px !important; |
|
} |
|
#cm-manual-button { |
|
width: 310px; |
|
height: 27px; |
|
position: relative; |
|
overflow: hidden; |
|
} |
|
|
|
.cm-button { |
|
width: 310px; |
|
height: 30px; |
|
position: relative; |
|
overflow: hidden; |
|
font-size: 17px !important; |
|
} |
|
|
|
.cm-button-red { |
|
width: 310px; |
|
height: 30px; |
|
position: relative; |
|
overflow: hidden; |
|
font-size: 17px !important; |
|
background-color: #500000 !important; |
|
color: white !important; |
|
} |
|
|
|
|
|
.cm-button-orange { |
|
width: 310px; |
|
height: 30px; |
|
position: relative; |
|
overflow: hidden; |
|
font-size: 17px !important; |
|
font-weight: bold; |
|
background-color: orange !important; |
|
color: black !important; |
|
} |
|
|
|
.cm-experimental-button { |
|
width: 290px; |
|
height: 30px; |
|
position: relative; |
|
overflow: hidden; |
|
font-size: 17px !important; |
|
} |
|
|
|
.cm-experimental { |
|
width: 310px; |
|
border: 1px solid #555; |
|
border-radius: 5px; |
|
padding: 10px; |
|
align-items: center; |
|
text-align: center; |
|
justify-content: center; |
|
box-sizing: border-box; |
|
} |
|
|
|
.cm-experimental-legend { |
|
margin-top: -20px; |
|
margin-left: 50%; |
|
width:auto; |
|
height:20px; |
|
font-size: 13px; |
|
font-weight: bold; |
|
background-color: #990000; |
|
color: #CCFFFF; |
|
border-radius: 5px; |
|
text-align: center; |
|
transform: translateX(-50%); |
|
display: block; |
|
} |
|
|
|
.cm-menu-combo { |
|
cursor: pointer; |
|
width: 310px; |
|
box-sizing: border-box; |
|
} |
|
|
|
.cm-small-button { |
|
width: 120px; |
|
height: 30px; |
|
position: relative; |
|
overflow: hidden; |
|
box-sizing: border-box; |
|
font-size: 17px !important; |
|
} |
|
|
|
#cm-install-customnodes-button { |
|
width: 200px; |
|
height: 30px; |
|
position: relative; |
|
overflow: hidden; |
|
box-sizing: border-box; |
|
font-size: 17px !important; |
|
} |
|
|
|
.cm-search-filter { |
|
width: 200px; |
|
height: 30px !important; |
|
position: relative; |
|
overflow: hidden; |
|
box-sizing: border-box; |
|
} |
|
|
|
.cb-node-label { |
|
width: 400px; |
|
height:28px; |
|
color: black; |
|
background-color: #777777; |
|
font-size: 18px; |
|
text-align: center; |
|
font-weight: bold; |
|
} |
|
|
|
#cm-close-button { |
|
width: calc(100% - 65px); |
|
bottom: 10px; |
|
position: absolute; |
|
overflow: hidden; |
|
} |
|
|
|
#cm-save-button { |
|
width: calc(100% - 65px); |
|
bottom:40px; |
|
position: absolute; |
|
overflow: hidden; |
|
} |
|
#cm-save-button:disabled { |
|
background-color: #444444; |
|
} |
|
|
|
.pysssss-workflow-arrow-2 { |
|
position: absolute; |
|
top: 0; |
|
bottom: 0; |
|
right: 0; |
|
font-size: 12px; |
|
display: flex; |
|
align-items: center; |
|
width: 24px; |
|
justify-content: center; |
|
background: rgba(255,255,255,0.1); |
|
content: "▼"; |
|
} |
|
.pysssss-workflow-arrow-2:after { |
|
content: "▼"; |
|
} |
|
.pysssss-workflow-arrow-2:hover { |
|
filter: brightness(1.6); |
|
background-color: var(--comfy-menu-bg); |
|
} |
|
.pysssss-workflow-popup-2 ~ .litecontextmenu { |
|
transform: scale(1.3); |
|
} |
|
#workflowgallery-button-menu { |
|
z-index: 10000000000 !important; |
|
} |
|
#cm-manual-button-menu { |
|
z-index: 10000000000 !important; |
|
} |
|
`; |
|
|
|
async function init_share_option() { |
|
api.fetchApi('/manager/share_option') |
|
.then(response => response.text()) |
|
.then(data => { |
|
share_option = data || 'all'; |
|
}); |
|
} |
|
|
|
async function init_notice(notice) { |
|
api.fetchApi('/manager/notice') |
|
.then(response => response.text()) |
|
.then(data => { |
|
notice.innerHTML = data; |
|
}) |
|
} |
|
|
|
await init_share_option(); |
|
|
|
|
|
async function set_inprogress_mode() { |
|
update_comfyui_button.disabled = true; |
|
update_comfyui_button.style.backgroundColor = "gray"; |
|
|
|
update_all_button.disabled = true; |
|
update_all_button.style.backgroundColor = "gray"; |
|
|
|
switch_comfyui_button.disabled = true; |
|
switch_comfyui_button.style.backgroundColor = "gray"; |
|
|
|
restart_stop_button.innerText = 'Stop'; |
|
} |
|
|
|
|
|
async function reset_action_buttons() { |
|
const isElectron = 'electronAPI' in window; |
|
|
|
if(isElectron) { |
|
update_all_button.innerText = "Update All Custom Nodes"; |
|
} |
|
else { |
|
update_all_button.innerText = "Update All"; |
|
} |
|
|
|
update_comfyui_button.innerText = "Update ComfyUI"; |
|
switch_comfyui_button.innerText = "Switch ComfyUI"; |
|
restart_stop_button.innerText = 'Restart'; |
|
|
|
update_comfyui_button.disabled = false; |
|
update_all_button.disabled = false; |
|
switch_comfyui_button.disabled = false; |
|
|
|
update_comfyui_button.style.backgroundColor = ""; |
|
update_all_button.style.backgroundColor = ""; |
|
switch_comfyui_button.style.backgroundColor = ""; |
|
} |
|
|
|
async function updateComfyUI() { |
|
let prev_text = update_comfyui_button.innerText; |
|
update_comfyui_button.innerText = "Updating ComfyUI..."; |
|
|
|
set_inprogress_mode(); |
|
|
|
const response = await api.fetchApi('/manager/queue/update_comfyui'); |
|
|
|
showTerminal(); |
|
|
|
is_updating = true; |
|
await api.fetchApi('/manager/queue/start'); |
|
} |
|
|
|
function showVersionSelectorDialog(versions, current, onSelect) { |
|
const dialog = new ComfyDialog(); |
|
dialog.element.style.zIndex = 1100; |
|
dialog.element.style.width = "300px"; |
|
dialog.element.style.padding = "0"; |
|
dialog.element.style.backgroundColor = "#2a2a2a"; |
|
dialog.element.style.border = "1px solid #3a3a3a"; |
|
dialog.element.style.borderRadius = "8px"; |
|
dialog.element.style.boxSizing = "border-box"; |
|
dialog.element.style.overflow = "hidden"; |
|
|
|
const contentStyle = { |
|
width: "300px", |
|
display: "flex", |
|
flexDirection: "column", |
|
alignItems: "center", |
|
padding: "20px", |
|
boxSizing: "border-box", |
|
gap: "15px" |
|
}; |
|
|
|
let selectedVersion = versions[0]; |
|
|
|
const versionList = $el("select", { |
|
multiple: true, |
|
size: Math.min(10, versions.length), |
|
style: { |
|
width: "260px", |
|
height: "auto", |
|
backgroundColor: "#383838", |
|
color: "#ffffff", |
|
border: "1px solid #4a4a4a", |
|
borderRadius: "4px", |
|
padding: "5px", |
|
boxSizing: "border-box" |
|
} |
|
}, |
|
versions.map((v, index) => $el("option", { |
|
value: v, |
|
textContent: v, |
|
selected: v === current |
|
})) |
|
); |
|
|
|
versionList.addEventListener('change', (e) => { |
|
selectedVersion = e.target.value; |
|
Array.from(e.target.options).forEach(opt => { |
|
opt.selected = opt.value === selectedVersion; |
|
}); |
|
}); |
|
|
|
const content = $el("div", { |
|
style: contentStyle |
|
}, [ |
|
$el("h3", { |
|
textContent: "Select Version", |
|
style: { |
|
color: "#ffffff", |
|
backgroundColor: "#1a1a1a", |
|
padding: "10px 15px", |
|
margin: "0 0 10px 0", |
|
width: "260px", |
|
textAlign: "center", |
|
borderRadius: "4px", |
|
boxSizing: "border-box", |
|
whiteSpace: "nowrap", |
|
overflow: "hidden", |
|
textOverflow: "ellipsis" |
|
} |
|
}), |
|
versionList, |
|
$el("div", { |
|
style: { |
|
display: "flex", |
|
justifyContent: "space-between", |
|
width: "260px", |
|
gap: "10px" |
|
} |
|
}, [ |
|
$el("button", { |
|
textContent: "Cancel", |
|
onclick: () => dialog.close(), |
|
style: { |
|
flex: "1", |
|
padding: "8px", |
|
backgroundColor: "#4a4a4a", |
|
color: "#ffffff", |
|
border: "none", |
|
borderRadius: "4px", |
|
cursor: "pointer", |
|
whiteSpace: "nowrap", |
|
overflow: "hidden", |
|
textOverflow: "ellipsis" |
|
} |
|
}), |
|
$el("button", { |
|
textContent: "Select", |
|
onclick: () => { |
|
if (selectedVersion) { |
|
onSelect(selectedVersion); |
|
dialog.close(); |
|
} else { |
|
customAlert("Please select a version."); |
|
} |
|
}, |
|
style: { |
|
flex: "1", |
|
padding: "8px", |
|
backgroundColor: "#4CAF50", |
|
color: "#ffffff", |
|
border: "none", |
|
borderRadius: "4px", |
|
cursor: "pointer", |
|
whiteSpace: "nowrap", |
|
overflow: "hidden", |
|
textOverflow: "ellipsis" |
|
} |
|
}), |
|
]) |
|
]); |
|
|
|
dialog.show(content); |
|
} |
|
|
|
async function switchComfyUI() { |
|
switch_comfyui_button.disabled = true; |
|
switch_comfyui_button.style.backgroundColor = "gray"; |
|
|
|
let res = await api.fetchApi(`/comfyui_manager/comfyui_versions`, { cache: "no-store" }); |
|
|
|
switch_comfyui_button.disabled = false; |
|
switch_comfyui_button.style.backgroundColor = ""; |
|
|
|
if(res.status == 200) { |
|
let obj = await res.json(); |
|
|
|
let versions = []; |
|
let default_version; |
|
|
|
for(let v of obj.versions) { |
|
default_version = v; |
|
versions.push(v); |
|
} |
|
|
|
showVersionSelectorDialog(versions, obj.current, async (selected_version) => { |
|
if(selected_version == 'nightly') { |
|
update_policy_combo.value = 'nightly-comfyui'; |
|
api.fetchApi('/manager/policy/update?value=nightly-comfyui'); |
|
} |
|
else { |
|
update_policy_combo.value = 'stable-comfyui'; |
|
api.fetchApi('/manager/policy/update?value=stable-comfyui'); |
|
} |
|
|
|
let response = await api.fetchApi(`/comfyui_manager/comfyui_switch_version?ver=${selected_version}`, { cache: "no-store" }); |
|
if (response.status == 200) { |
|
infoToast(`ComfyUI version is switched to ${selected_version}`); |
|
} |
|
else { |
|
customAlert('Failed to switch ComfyUI version.'); |
|
} |
|
}); |
|
} |
|
else { |
|
customAlert('Failed to fetch ComfyUI versions.'); |
|
} |
|
} |
|
|
|
async function onQueueStatus(event) { |
|
const isElectron = 'electronAPI' in window; |
|
|
|
if(event.detail.status == 'in_progress') { |
|
set_inprogress_mode(); |
|
update_all_button.innerText = `in progress.. (${event.detail.done_count}/${event.detail.total_count})`; |
|
} |
|
else if(event.detail.status == 'done') { |
|
reset_action_buttons(); |
|
|
|
if(!is_updating) { |
|
return; |
|
} |
|
|
|
is_updating = false; |
|
|
|
let success_list = []; |
|
let failed_list = []; |
|
let comfyui_state = null; |
|
|
|
for(let k in event.detail.nodepack_result){ |
|
let v = event.detail.nodepack_result[k]; |
|
|
|
if(k == 'comfyui') { |
|
comfyui_state = v; |
|
continue; |
|
} |
|
|
|
if(v.msg == 'success') { |
|
success_list.push(k); |
|
} |
|
else if(v.msg != 'skip') |
|
failed_list.push(k); |
|
} |
|
|
|
let msg = ""; |
|
|
|
if(success_list.length == 0 && comfyui_state.startsWith('skip')) { |
|
if(failed_list.length == 0) { |
|
msg += "You are already up to date."; |
|
} |
|
} |
|
else { |
|
msg = "To apply the updates, you need to <button class='cm-small-button' id='cm-reboot-button5'>RESTART</button> ComfyUI.<hr>"; |
|
|
|
if(comfyui_state == 'success-nightly') { |
|
msg += "ComfyUI has been updated to latest nightly version.<BR><BR>"; |
|
infoToast("ComfyUI has been updated to the latest nightly version."); |
|
} |
|
else if(comfyui_state.startsWith('success-stable')) { |
|
const ver = comfyui_state.split("-").pop(); |
|
msg += `ComfyUI has been updated to ${ver}.<BR><BR>`; |
|
infoToast(`ComfyUI has been updated to ${ver}`); |
|
} |
|
else if(comfyui_state == 'skip') { |
|
msg += "ComfyUI is already up to date.<BR><BR>" |
|
} |
|
else if(comfyui_state != null) { |
|
msg += "Failed to update ComfyUI.<BR><BR>" |
|
} |
|
|
|
if(success_list.length > 0) { |
|
msg += "The following custom nodes have been updated:<ul>"; |
|
for(let x in success_list) { |
|
let k = success_list[x]; |
|
let url = event.detail.nodepack_result[k].url; |
|
let title = event.detail.nodepack_result[k].title; |
|
if(url) { |
|
msg += `<li><a href='${url}' target='_blank'>${title}</a></li>`; |
|
} |
|
else { |
|
msg += `<li>${k}</li>`; |
|
} |
|
} |
|
msg += "</ul>"; |
|
} |
|
|
|
setNeedRestart(true); |
|
} |
|
|
|
if(failed_list.length > 0) { |
|
msg += '<br>The update for the following custom nodes has failed:<ul>'; |
|
for(let x in failed_list) { |
|
let k = failed_list[x]; |
|
let url = event.detail.nodepack_result[k].url; |
|
let title = event.detail.nodepack_result[k].title; |
|
if(url) { |
|
msg += `<li><a href='${url}' target='_blank'>${title}</a></li>`; |
|
} |
|
else { |
|
msg += `<li>${k}</li>`; |
|
} |
|
} |
|
|
|
msg += '</ul>' |
|
} |
|
|
|
show_message(msg); |
|
|
|
const rebootButton = document.getElementById('cm-reboot-button5'); |
|
rebootButton?.addEventListener("click", |
|
function() { |
|
if(rebootAPI()) { |
|
manager_dialog.close(); |
|
} |
|
}); |
|
} |
|
} |
|
|
|
api.addEventListener("cm-queue-status", onQueueStatus); |
|
|
|
|
|
async function updateAll(update_comfyui) { |
|
update_all_button.innerText = "Updating..."; |
|
|
|
set_inprogress_mode(); |
|
|
|
var mode = manager_instance.datasrc_combo.value; |
|
|
|
showTerminal(); |
|
|
|
if(update_comfyui) { |
|
update_all_button.innerText = "Updating ComfyUI..."; |
|
await api.fetchApi('/manager/queue/update_comfyui'); |
|
} |
|
|
|
const response = await api.fetchApi(`/manager/queue/update_all?mode=${mode}`); |
|
|
|
if (response.status == 401) { |
|
customAlert('Another task is already in progress. Please stop the ongoing task first.'); |
|
} |
|
else if(response.status == 200) { |
|
is_updating = true; |
|
await api.fetchApi('/manager/queue/start'); |
|
} |
|
} |
|
|
|
function newDOMTokenList(initialTokens) { |
|
const tmp = document.createElement(`div`); |
|
|
|
const classList = tmp.classList; |
|
if (initialTokens) { |
|
initialTokens.forEach(token => { |
|
classList.add(token); |
|
}); |
|
} |
|
|
|
return classList; |
|
} |
|
|
|
|
|
|
|
|
|
const isOutputNode = (node) => { |
|
return SUPPORTED_OUTPUT_NODE_TYPES.includes(node.type); |
|
} |
|
|
|
function restartOrStop() { |
|
if(restart_stop_button.innerText == 'Restart'){ |
|
rebootAPI(); |
|
} |
|
else { |
|
api.fetchApi('/manager/queue/reset'); |
|
infoToast('Cancel', 'Remaining tasks will stop after completing the current task.'); |
|
} |
|
} |
|
|
|
|
|
class ManagerMenuDialog extends ComfyDialog { |
|
createControlsMid() { |
|
let self = this; |
|
const isElectron = 'electronAPI' in window; |
|
|
|
update_comfyui_button = |
|
$el("button.cm-button", { |
|
type: "button", |
|
textContent: "Update ComfyUI", |
|
style: { |
|
display: isElectron ? 'none' : 'block' |
|
}, |
|
onclick: |
|
() => updateComfyUI() |
|
}); |
|
|
|
switch_comfyui_button = |
|
$el("button.cm-button", { |
|
type: "button", |
|
textContent: "Switch ComfyUI", |
|
style: { |
|
display: isElectron ? 'none' : 'block' |
|
}, |
|
onclick: |
|
() => switchComfyUI() |
|
}); |
|
|
|
restart_stop_button = |
|
$el("button.cm-button-red", { |
|
type: "button", |
|
textContent: "Restart", |
|
onclick: () => restartOrStop() |
|
}); |
|
|
|
if(isElectron) { |
|
update_all_button = |
|
$el("button.cm-button", { |
|
type: "button", |
|
textContent: "Update All Custom Nodes", |
|
onclick: |
|
() => updateAll(false) |
|
}); |
|
} |
|
else { |
|
update_all_button = |
|
$el("button.cm-button", { |
|
type: "button", |
|
textContent: "Update All", |
|
onclick: |
|
() => updateAll(true) |
|
}); |
|
} |
|
|
|
const res = |
|
[ |
|
$el("button.cm-button", { |
|
type: "button", |
|
textContent: "Custom Nodes Manager", |
|
onclick: |
|
() => { |
|
if(!CustomNodesManager.instance) { |
|
CustomNodesManager.instance = new CustomNodesManager(app, self); |
|
} |
|
CustomNodesManager.instance.show(CustomNodesManager.ShowMode.NORMAL); |
|
} |
|
}), |
|
|
|
$el("button.cm-button", { |
|
type: "button", |
|
textContent: "Install Missing Custom Nodes", |
|
onclick: |
|
() => { |
|
if(!CustomNodesManager.instance) { |
|
CustomNodesManager.instance = new CustomNodesManager(app, self); |
|
} |
|
CustomNodesManager.instance.show(CustomNodesManager.ShowMode.MISSING); |
|
} |
|
}), |
|
|
|
$el("button.cm-button", { |
|
type: "button", |
|
textContent: "Custom Nodes In Workflow", |
|
onclick: |
|
() => { |
|
if(!CustomNodesManager.instance) { |
|
CustomNodesManager.instance = new CustomNodesManager(app, self); |
|
} |
|
CustomNodesManager.instance.show(CustomNodesManager.ShowMode.IN_WORKFLOW); |
|
} |
|
}), |
|
|
|
$el("br", {}, []), |
|
$el("button.cm-button", { |
|
type: "button", |
|
textContent: "Model Manager", |
|
onclick: |
|
() => { |
|
if(!ModelManager.instance) { |
|
ModelManager.instance = new ModelManager(app, self); |
|
} |
|
ModelManager.instance.show(); |
|
} |
|
}), |
|
|
|
$el("button.cm-button", { |
|
type: "button", |
|
textContent: "Install via Git URL", |
|
onclick: async () => { |
|
var url = await customPrompt("Please enter the URL of the Git repository to install", ""); |
|
|
|
if (url !== null) { |
|
install_via_git_url(url, self); |
|
} |
|
} |
|
}), |
|
|
|
$el("br", {}, []), |
|
update_all_button, |
|
update_comfyui_button, |
|
switch_comfyui_button, |
|
|
|
|
|
$el("br", {}, []), |
|
restart_stop_button, |
|
]; |
|
|
|
return res; |
|
} |
|
|
|
createControlsLeft() { |
|
const isElectron = 'electronAPI' in window; |
|
|
|
let self = this; |
|
|
|
|
|
this.datasrc_combo = document.createElement("select"); |
|
this.datasrc_combo.setAttribute("title", "Configure where to retrieve node/model information. If set to 'local,' the channel is ignored, and if set to 'channel (remote),' it fetches the latest information each time the list is opened."); |
|
this.datasrc_combo.className = "cm-menu-combo"; |
|
this.datasrc_combo.appendChild($el('option', { value: 'cache', text: 'DB: Channel (1day cache)' }, [])); |
|
this.datasrc_combo.appendChild($el('option', { value: 'local', text: 'DB: Local' }, [])); |
|
this.datasrc_combo.appendChild($el('option', { value: 'remote', text: 'DB: Channel (remote)' }, [])); |
|
|
|
api.fetchApi('/manager/db_mode') |
|
.then(response => response.text()) |
|
.then(data => { this.datasrc_combo.value = data; }); |
|
|
|
this.datasrc_combo.addEventListener('change', function (event) { |
|
api.fetchApi(`/manager/db_mode?value=${event.target.value}`); |
|
}); |
|
|
|
|
|
let preview_combo = document.createElement("select"); |
|
preview_combo.setAttribute("title", "Configure how latent variables will be decoded during preview in the sampling process."); |
|
preview_combo.className = "cm-menu-combo"; |
|
preview_combo.appendChild($el('option', { value: 'auto', text: 'Preview method: Auto' }, [])); |
|
preview_combo.appendChild($el('option', { value: 'taesd', text: 'Preview method: TAESD (slow)' }, [])); |
|
preview_combo.appendChild($el('option', { value: 'latent2rgb', text: 'Preview method: Latent2RGB (fast)' }, [])); |
|
preview_combo.appendChild($el('option', { value: 'none', text: 'Preview method: None (very fast)' }, [])); |
|
|
|
api.fetchApi('/manager/preview_method') |
|
.then(response => response.text()) |
|
.then(data => { preview_combo.value = data; }); |
|
|
|
preview_combo.addEventListener('change', function (event) { |
|
api.fetchApi(`/manager/preview_method?value=${event.target.value}`); |
|
}); |
|
|
|
|
|
let channel_combo = document.createElement("select"); |
|
channel_combo.setAttribute("title", "Configure the channel for retrieving data from the Custom Node list (including missing nodes) or the Model list."); |
|
channel_combo.className = "cm-menu-combo"; |
|
api.fetchApi('/manager/channel_url_list') |
|
.then(response => response.json()) |
|
.then(async data => { |
|
try { |
|
let urls = data.list; |
|
for (let i in urls) { |
|
if (urls[i] != '') { |
|
let name_url = urls[i].split('::'); |
|
channel_combo.appendChild($el('option', { value: name_url[0], text: `Channel: ${name_url[0]}` }, [])); |
|
} |
|
} |
|
|
|
channel_combo.addEventListener('change', function (event) { |
|
api.fetchApi(`/manager/channel_url_list?value=${event.target.value}`); |
|
}); |
|
|
|
channel_combo.value = data.selected; |
|
} |
|
catch (exception) { |
|
|
|
} |
|
}); |
|
|
|
|
|
|
|
let share_combo = document.createElement("select"); |
|
share_combo.setAttribute("title", "Hide the share button in the main menu or set the default action upon clicking it. Additionally, configure the default share site when sharing via the context menu's share button."); |
|
share_combo.className = "cm-menu-combo"; |
|
const share_options = [ |
|
['none', 'None'], |
|
['openart', 'OpenArt AI'], |
|
['youml', 'YouML'], |
|
['matrix', 'Matrix Server'], |
|
['comfyworkflows', 'ComfyWorkflows'], |
|
['copus', 'Copus'], |
|
['all', 'All'], |
|
]; |
|
for (const option of share_options) { |
|
share_combo.appendChild($el('option', { value: option[0], text: `Share: ${option[1]}` }, [])); |
|
} |
|
|
|
api.fetchApi('/manager/share_option') |
|
.then(response => response.text()) |
|
.then(data => { |
|
share_combo.value = data || 'all'; |
|
share_option = data || 'all'; |
|
}); |
|
|
|
share_combo.addEventListener('change', function (event) { |
|
const value = event.target.value; |
|
share_option = value; |
|
api.fetchApi(`/manager/share_option?value=${value}`); |
|
const shareButton = document.getElementById("shareButton"); |
|
if (value === 'none') { |
|
shareButton.style.display = "none"; |
|
} else { |
|
shareButton.style.display = "inline-block"; |
|
} |
|
}); |
|
|
|
let component_policy_combo = document.createElement("select"); |
|
component_policy_combo.setAttribute("title", "When loading the workflow, configure which version of the component to use."); |
|
component_policy_combo.className = "cm-menu-combo"; |
|
component_policy_combo.appendChild($el('option', { value: 'workflow', text: 'Component: Use workflow version' }, [])); |
|
component_policy_combo.appendChild($el('option', { value: 'higher', text: 'Component: Use higher version' }, [])); |
|
component_policy_combo.appendChild($el('option', { value: 'mine', text: 'Component: Use my version' }, [])); |
|
api.fetchApi('/manager/policy/component') |
|
.then(response => response.text()) |
|
.then(data => { |
|
component_policy_combo.value = data; |
|
set_component_policy(data); |
|
}); |
|
|
|
component_policy_combo.addEventListener('change', function (event) { |
|
api.fetchApi(`/manager/policy/component?value=${event.target.value}`); |
|
set_component_policy(event.target.value); |
|
}); |
|
|
|
update_policy_combo = document.createElement("select"); |
|
|
|
if(isElectron) |
|
update_policy_combo.style.display = 'none'; |
|
|
|
update_policy_combo.setAttribute("title", "Sets the policy to be applied when performing an update."); |
|
update_policy_combo.className = "cm-menu-combo"; |
|
update_policy_combo.appendChild($el('option', { value: 'stable-comfyui', text: 'Update: ComfyUI Stable Version' }, [])); |
|
update_policy_combo.appendChild($el('option', { value: 'nightly-comfyui', text: 'Update: ComfyUI Nightly Version' }, [])); |
|
api.fetchApi('/manager/policy/update') |
|
.then(response => response.text()) |
|
.then(data => { |
|
update_policy_combo.value = data; |
|
}); |
|
|
|
update_policy_combo.addEventListener('change', function (event) { |
|
api.fetchApi(`/manager/policy/update?value=${event.target.value}`); |
|
}); |
|
|
|
return [ |
|
$el("br", {}, []), |
|
this.datasrc_combo, |
|
channel_combo, |
|
preview_combo, |
|
share_combo, |
|
component_policy_combo, |
|
update_policy_combo, |
|
$el("br", {}, []), |
|
|
|
$el("br", {}, []), |
|
$el("filedset.cm-experimental", {}, [ |
|
$el("legend.cm-experimental-legend", {}, ["EXPERIMENTAL"]), |
|
$el("button.cm-experimental-button", { |
|
type: "button", |
|
textContent: "Snapshot Manager", |
|
onclick: |
|
() => { |
|
if(!SnapshotManager.instance) |
|
SnapshotManager.instance = new SnapshotManager(app, self); |
|
SnapshotManager.instance.show(); |
|
} |
|
}), |
|
$el("button.cm-experimental-button", { |
|
type: "button", |
|
textContent: "Install PIP packages", |
|
onclick: |
|
async () => { |
|
var url = await customPrompt("Please enumerate the pip packages to be installed.\n\nExample: insightface opencv-python-headless>=4.1.1\n", ""); |
|
|
|
if (url !== null) { |
|
install_pip(url, self); |
|
} |
|
} |
|
}) |
|
]), |
|
]; |
|
} |
|
|
|
createControlsRight() { |
|
const elts = [ |
|
$el("button.cm-button", { |
|
id: 'cm-manual-button', |
|
type: "button", |
|
textContent: "Community Manual", |
|
onclick: () => { window.open("https://blenderneko.github.io/ComfyUI-docs/", "comfyui-community-manual"); } |
|
}, [ |
|
$el("div.pysssss-workflow-arrow-2", { |
|
id: `cm-manual-button-arrow`, |
|
onclick: (e) => { |
|
e.preventDefault(); |
|
e.stopPropagation(); |
|
|
|
LiteGraph.closeAllContextMenus(); |
|
const menu = new LiteGraph.ContextMenu( |
|
[ |
|
{ |
|
title: "ComfyUI Docs", |
|
callback: () => { window.open("https://docs.comfy.org/", "comfyui-official-manual"); }, |
|
}, |
|
{ |
|
title: "Comfy Custom Node How To", |
|
callback: () => { window.open("https://github.com/chrisgoringe/Comfy-Custom-Node-How-To/wiki/aaa_index", "comfyui-community-manual1"); }, |
|
}, |
|
{ |
|
title: "ComfyUI Guide To Making Custom Nodes", |
|
callback: () => { window.open("https://github.com/Suzie1/ComfyUI_Guide_To_Making_Custom_Nodes/wiki", "comfyui-community-manual2"); }, |
|
}, |
|
{ |
|
title: "ComfyUI Examples", |
|
callback: () => { window.open("https://comfyanonymous.github.io/ComfyUI_examples", "comfyui-community-manual3"); }, |
|
}, |
|
{ |
|
title: "Close", |
|
callback: () => { |
|
LiteGraph.closeAllContextMenus(); |
|
}, |
|
} |
|
], |
|
{ |
|
event: e, |
|
scale: 1.3, |
|
}, |
|
window |
|
); |
|
|
|
menu.root.id = "cm-manual-button-menu"; |
|
menu.root.classList.add("pysssss-workflow-popup-2"); |
|
}, |
|
}) |
|
]), |
|
|
|
$el("button", { |
|
id: 'workflowgallery-button', |
|
type: "button", |
|
style: { |
|
...(localStorage.getItem("wg_last_visited") ? {height: '50px'} : {}) |
|
}, |
|
onclick: (e) => { |
|
const last_visited_site = localStorage.getItem("wg_last_visited") |
|
if (!!last_visited_site) { |
|
window.open(last_visited_site, last_visited_site); |
|
} else { |
|
this.handleWorkflowGalleryButtonClick(e) |
|
} |
|
}, |
|
}, [ |
|
$el("p", { |
|
textContent: 'Workflow Gallery', |
|
style: { |
|
'text-align': 'center', |
|
'color': 'var(--input-text)', |
|
'font-size': '18px', |
|
'margin': 0, |
|
'padding': 0, |
|
} |
|
}, [ |
|
$el("p", { |
|
id: 'workflowgallery-button-last-visited-label', |
|
textContent: `(${localStorage.getItem("wg_last_visited") ? localStorage.getItem("wg_last_visited").split('/')[2] : ''})`, |
|
style: { |
|
'text-align': 'center', |
|
'color': 'var(--input-text)', |
|
'font-size': '12px', |
|
'margin': 0, |
|
'padding': 0, |
|
} |
|
}) |
|
]), |
|
$el("div.pysssss-workflow-arrow-2", { |
|
id: `comfyworkflows-button-arrow`, |
|
onclick: this.handleWorkflowGalleryButtonClick |
|
}) |
|
]), |
|
|
|
$el("button.cm-button", { |
|
id: 'cm-nodeinfo-button', |
|
type: "button", |
|
textContent: "Nodes Info", |
|
onclick: () => { window.open("https://ltdrdata.github.io/", "comfyui-node-info"); } |
|
}), |
|
$el("br", {}, []), |
|
]; |
|
|
|
var textarea = document.createElement("div"); |
|
textarea.className = "cm-notice-board"; |
|
elts.push(textarea); |
|
|
|
init_notice(textarea); |
|
|
|
return elts; |
|
} |
|
|
|
constructor() { |
|
super(); |
|
|
|
const close_button = $el("button", { id: "cm-close-button", type: "button", textContent: "Close", onclick: () => this.close() }); |
|
|
|
const content = |
|
$el("div.comfy-modal-content", |
|
[ |
|
$el("tr.cm-title", {}, [ |
|
$el("font", {size:6, color:"white"}, [`ComfyUI Manager ${manager_version}`])] |
|
), |
|
$el("br", {}, []), |
|
$el("div.cm-menu-container", |
|
[ |
|
$el("div.cm-menu-column", [...this.createControlsLeft()]), |
|
$el("div.cm-menu-column", [...this.createControlsMid()]), |
|
$el("div.cm-menu-column", [...this.createControlsRight()]) |
|
]), |
|
|
|
$el("br", {}, []), |
|
close_button, |
|
] |
|
); |
|
|
|
content.style.width = '100%'; |
|
content.style.height = '100%'; |
|
|
|
this.element = $el("div.comfy-modal", { id:'cm-manager-dialog', parent: document.body }, [ content ]); |
|
} |
|
|
|
get isVisible() { |
|
return this.element?.style?.display !== "none"; |
|
} |
|
|
|
show() { |
|
this.element.style.display = "block"; |
|
} |
|
|
|
toggleVisibility() { |
|
if (this.isVisible) { |
|
this.close(); |
|
} else { |
|
this.show(); |
|
} |
|
} |
|
|
|
handleWorkflowGalleryButtonClick(e) { |
|
e.preventDefault(); |
|
e.stopPropagation(); |
|
LiteGraph.closeAllContextMenus(); |
|
|
|
|
|
|
|
const modifyButtonStyle = (url) => { |
|
const workflowGalleryButton = document.getElementById('workflowgallery-button'); |
|
workflowGalleryButton.style.height = '50px'; |
|
const lastVisitedLabel = document.getElementById('workflowgallery-button-last-visited-label'); |
|
lastVisitedLabel.textContent = `(${url.split('/')[2]})`; |
|
} |
|
|
|
const menu = new LiteGraph.ContextMenu( |
|
[ |
|
{ |
|
title: "Share your art", |
|
callback: () => { |
|
if (share_option === 'openart') { |
|
showOpenArtShareDialog(); |
|
return; |
|
} else if (share_option === 'matrix' || share_option === 'comfyworkflows') { |
|
showShareDialog(share_option); |
|
return; |
|
} else if (share_option === 'youml') { |
|
showYouMLShareDialog(); |
|
return; |
|
} |
|
|
|
if (!ShareDialogChooser.instance) { |
|
ShareDialogChooser.instance = new ShareDialogChooser(); |
|
} |
|
ShareDialogChooser.instance.show(); |
|
}, |
|
}, |
|
{ |
|
title: "Open 'openart.ai'", |
|
callback: () => { |
|
const url = "https://openart.ai/workflows/dev"; |
|
localStorage.setItem("wg_last_visited", url); |
|
window.open(url, url); |
|
modifyButtonStyle(url); |
|
}, |
|
}, |
|
{ |
|
title: "Open 'youml.com'", |
|
callback: () => { |
|
const url = "https://youml.com/?from=comfyui-share"; |
|
localStorage.setItem("wg_last_visited", url); |
|
window.open(url, url); |
|
modifyButtonStyle(url); |
|
}, |
|
}, |
|
{ |
|
title: "Open 'comfyworkflows.com'", |
|
callback: () => { |
|
const url = "https://comfyworkflows.com/"; |
|
localStorage.setItem("wg_last_visited", url); |
|
window.open(url, url); |
|
modifyButtonStyle(url); |
|
}, |
|
}, |
|
{ |
|
title: "Open 'esheep'", |
|
callback: () => { |
|
const url = "https://www.esheep.com"; |
|
localStorage.setItem("wg_last_visited", url); |
|
window.open(url, url); |
|
modifyButtonStyle(url); |
|
}, |
|
}, |
|
{ |
|
title: "Open 'Copus.io'", |
|
callback: () => { |
|
const url = "https://www.copus.io"; |
|
localStorage.setItem("wg_last_visited", url); |
|
window.open(url, url); |
|
modifyButtonStyle(url); |
|
}, |
|
}, |
|
{ |
|
title: "Close", |
|
callback: () => { |
|
LiteGraph.closeAllContextMenus(); |
|
}, |
|
} |
|
], |
|
{ |
|
event: e, |
|
scale: 1.3, |
|
}, |
|
window |
|
); |
|
|
|
menu.root.id = "workflowgallery-button-menu"; |
|
menu.root.classList.add("pysssss-workflow-popup-2"); |
|
} |
|
} |
|
|
|
async function getVersion() { |
|
let version = await api.fetchApi(`/manager/version`); |
|
return await version.text(); |
|
} |
|
|
|
app.registerExtension({ |
|
name: "Comfy.ManagerMenu", |
|
|
|
aboutPageBadges: [ |
|
{ |
|
label: `ComfyUI-Manager ${manager_version}`, |
|
url: 'https://github.com/ltdrdata/ComfyUI-Manager', |
|
icon: 'pi pi-th-large' |
|
} |
|
], |
|
|
|
commands: [ |
|
{ |
|
id: "Comfy.Manager.Menu.ToggleVisibility", |
|
label: "Toggle Manager Menu Visibility", |
|
icon: "mdi mdi-puzzle", |
|
function: () => { |
|
if (!manager_instance) { |
|
setManagerInstance(new ManagerMenuDialog()); |
|
manager_instance.show(); |
|
} else { |
|
manager_instance.toggleVisibility(); |
|
} |
|
}, |
|
}, |
|
{ |
|
id: "Comfy.Manager.CustomNodesManager.ToggleVisibility", |
|
label: "Toggle Custom Nodes Manager Visibility", |
|
icon: "pi pi-server", |
|
function: () => { |
|
if (CustomNodesManager.instance?.isVisible) { |
|
CustomNodesManager.instance.close(); |
|
return; |
|
} |
|
|
|
if (!manager_instance) { |
|
setManagerInstance(new ManagerMenuDialog()); |
|
} |
|
if (!CustomNodesManager.instance) { |
|
CustomNodesManager.instance = new CustomNodesManager(app, self); |
|
} |
|
CustomNodesManager.instance.show(CustomNodesManager.ShowMode.NORMAL); |
|
}, |
|
} |
|
], |
|
|
|
init() { |
|
$el("style", { |
|
textContent: style, |
|
parent: document.head, |
|
}); |
|
}, |
|
async setup() { |
|
let orig_clear = app.graph.clear; |
|
app.graph.clear = function () { |
|
orig_clear.call(app.graph); |
|
load_components(); |
|
}; |
|
|
|
load_components(); |
|
|
|
const menu = document.querySelector(".comfy-menu"); |
|
const separator = document.createElement("hr"); |
|
|
|
separator.style.margin = "20px 0"; |
|
separator.style.width = "100%"; |
|
menu.append(separator); |
|
|
|
try { |
|
|
|
|
|
let cmGroup = new (await import("../../scripts/ui/components/buttonGroup.js")).ComfyButtonGroup( |
|
new(await import("../../scripts/ui/components/button.js")).ComfyButton({ |
|
icon: "puzzle", |
|
action: () => { |
|
if(!manager_instance) |
|
setManagerInstance(new ManagerMenuDialog()); |
|
manager_instance.show(); |
|
}, |
|
tooltip: "ComfyUI Manager", |
|
content: "Manager", |
|
classList: "comfyui-button comfyui-menu-mobile-collapse primary" |
|
}).element, |
|
new(await import("../../scripts/ui/components/button.js")).ComfyButton({ |
|
icon: "star", |
|
action: () => { |
|
if(!manager_instance) |
|
setManagerInstance(new ManagerMenuDialog()); |
|
|
|
if(!CustomNodesManager.instance) { |
|
CustomNodesManager.instance = new CustomNodesManager(app, self); |
|
} |
|
CustomNodesManager.instance.show(CustomNodesManager.ShowMode.FAVORITES); |
|
}, |
|
tooltip: "Show favorite custom node list" |
|
}).element, |
|
new(await import("../../scripts/ui/components/button.js")).ComfyButton({ |
|
icon: "vacuum-outline", |
|
action: () => { |
|
free_models(); |
|
}, |
|
tooltip: "Unload Models" |
|
}).element, |
|
new(await import("../../scripts/ui/components/button.js")).ComfyButton({ |
|
icon: "vacuum", |
|
action: () => { |
|
free_models(true); |
|
}, |
|
tooltip: "Free model and node cache" |
|
}).element, |
|
new(await import("../../scripts/ui/components/button.js")).ComfyButton({ |
|
icon: "share", |
|
action: () => { |
|
if (share_option === 'openart') { |
|
showOpenArtShareDialog(); |
|
return; |
|
} else if (share_option === 'matrix' || share_option === 'comfyworkflows') { |
|
showShareDialog(share_option); |
|
return; |
|
} else if (share_option === 'youml') { |
|
showYouMLShareDialog(); |
|
return; |
|
} |
|
|
|
if(!ShareDialogChooser.instance) { |
|
ShareDialogChooser.instance = new ShareDialogChooser(); |
|
} |
|
ShareDialogChooser.instance.show(); |
|
}, |
|
tooltip: "Share" |
|
}).element |
|
); |
|
|
|
app.menu?.settingsGroup.element.before(cmGroup.element); |
|
} |
|
catch(exception) { |
|
console.log('ComfyUI is outdated. New style menu based features are disabled.'); |
|
} |
|
|
|
|
|
const managerButton = document.createElement("button"); |
|
managerButton.textContent = "Manager"; |
|
managerButton.onclick = () => { |
|
if(!manager_instance) |
|
setManagerInstance(new ManagerMenuDialog()); |
|
manager_instance.show(); |
|
} |
|
menu.append(managerButton); |
|
|
|
const shareButton = document.createElement("button"); |
|
shareButton.id = "shareButton"; |
|
shareButton.textContent = "Share"; |
|
shareButton.onclick = () => { |
|
if (share_option === 'openart') { |
|
showOpenArtShareDialog(); |
|
return; |
|
} else if (share_option === 'matrix' || share_option === 'comfyworkflows') { |
|
showShareDialog(share_option); |
|
return; |
|
} else if (share_option === 'youml') { |
|
showYouMLShareDialog(); |
|
return; |
|
} |
|
|
|
if(!ShareDialogChooser.instance) { |
|
ShareDialogChooser.instance = new ShareDialogChooser(); |
|
} |
|
ShareDialogChooser.instance.show(); |
|
} |
|
|
|
shareButton.style.background = "linear-gradient(90deg, #00C9FF 0%, #92FE9D 100%)"; |
|
shareButton.style.color = "black"; |
|
|
|
|
|
|
|
const shouldShowShareButton = share_option !== 'none'; |
|
shareButton.style.display = shouldShowShareButton ? "inline-block" : "none"; |
|
|
|
menu.append(shareButton); |
|
}, |
|
|
|
async beforeRegisterNodeDef(nodeType, nodeData, app) { |
|
this._addExtraNodeContextMenu(nodeType, app); |
|
}, |
|
|
|
_addExtraNodeContextMenu(node, app) { |
|
const origGetExtraMenuOptions = node.prototype.getExtraMenuOptions; |
|
node.prototype.cm_menu_added = true; |
|
node.prototype.getExtraMenuOptions = function (_, options) { |
|
origGetExtraMenuOptions?.apply?.(this, arguments); |
|
|
|
if (node.category.startsWith('group nodes>')) { |
|
options.push({ |
|
content: "Save As Component", |
|
callback: (obj) => { |
|
if (!ComponentBuilderDialog.instance) { |
|
ComponentBuilderDialog.instance = new ComponentBuilderDialog(); |
|
} |
|
ComponentBuilderDialog.instance.target_node = node; |
|
ComponentBuilderDialog.instance.show(); |
|
} |
|
}, null); |
|
} |
|
|
|
if (isOutputNode(node)) { |
|
const { potential_outputs } = getPotentialOutputsAndOutputNodes([this]); |
|
const hasOutput = potential_outputs.length > 0; |
|
|
|
|
|
|
|
if (options[options.length - 1] !== null) { |
|
options.push(null); |
|
} |
|
|
|
options.push({ |
|
content: "🏞️ Share Output", |
|
disabled: !hasOutput, |
|
callback: (obj) => { |
|
if (!ShareDialog.instance) { |
|
ShareDialog.instance = new ShareDialog(); |
|
} |
|
const shareButton = document.getElementById("shareButton"); |
|
if (shareButton) { |
|
const currentNode = this; |
|
if (!OpenArtShareDialog.instance) { |
|
OpenArtShareDialog.instance = new OpenArtShareDialog(); |
|
} |
|
OpenArtShareDialog.instance.selectedNodeId = currentNode.id; |
|
if (!ShareDialog.instance) { |
|
ShareDialog.instance = new ShareDialog(share_option); |
|
} |
|
ShareDialog.instance.selectedNodeId = currentNode.id; |
|
shareButton.click(); |
|
} |
|
} |
|
}, null); |
|
} |
|
} |
|
}, |
|
}); |
|
|