Browse Source

fix: log file permission issue when reboot on windows

enhance: pretty conflict nodes message
pull/200/head
Dr.Lt.Data 12 months ago
parent
commit
86fe6b317e
  1. 10
      __init__.py
  2. 224
      js/comfyui-manager.js
  3. 2
      js/common.js
  4. 248
      js/custom-nodes-downloader.js
  5. 2
      js/snapshot.js
  6. 11
      prestartup_script.py

10
__init__.py

@ -15,8 +15,9 @@ import ssl
from urllib.parse import urlparse
import http.client
import re
import signal
version = "V1.5"
version = "V1.5.1"
print(f"### Loading: ComfyUI-Manager ({version})")
@ -1479,7 +1480,12 @@ async def get_notice(request):
@server.PromptServer.instance.routes.get("/manager/reboot")
def restart(self):
return os.execv(sys.executable, ['python'] + sys.argv)
try:
sys.stdout.close_log()
except Exception as e:
pass
return os.execv(sys.executable, [sys.executable] + sys.argv)
@server.PromptServer.instance.routes.get("/manager/share_option")

224
js/comfyui-manager.js vendored

@ -12,15 +12,15 @@ import { manager_instance, setManagerInstance, install_via_git_url, rebootAPI }
var docStyle = document.createElement('style');
docStyle.innerHTML = `
.cm-menu-container {
column-gap: 20px;
display: flex;
flex-wrap: wrap;
justify-content: center;
column-gap: 20px;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.cm-menu-column {
display: flex;
flex-direction: column;
display: flex;
flex-direction: column;
}
.cm-title {
@ -38,7 +38,15 @@ docStyle.innerHTML = `
border: 1px solid #ccc;
padding: 10px;
overflow-x: hidden;
};
}
.cm-conflicted-nodes-text {
background-color: #CCCC55 !important;
color: #AA3333 !important;
font-size: 10px;
border-radius: 5px;
padding: 5px;
}
`;
document.head.appendChild(docStyle);
@ -56,17 +64,17 @@ const style = `
overflow: hidden;
}
.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: "▼";
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: "▼";
@ -92,10 +100,10 @@ async function init_badge_mode() {
}
async function init_share_option() {
api.fetchApi('/manager/share_option')
.then(response => response.text())
api.fetchApi('/manager/share_option')
.then(response => response.text())
.then(data => {
share_option = data || 'all';
share_option = data || 'all';
});
}
@ -184,8 +192,8 @@ async function fetchUpdates(update_check_checkbox) {
try {
var mode = "url";
if(manager_instance.local_mode_checkbox.checked)
mode = "local";
if(manager_instance.local_mode_checkbox.checked)
mode = "local";
const response = await api.fetchApi(`/customnode/fetch_updates?mode=${mode}`);
@ -227,8 +235,8 @@ async function updateAll(update_check_checkbox, manager_dialog) {
try {
var mode = "url";
if(manager_instance.local_mode_checkbox.checked)
mode = "local";
if(manager_instance.local_mode_checkbox.checked)
mode = "local";
update_all_button.innerText = "Updating all...";
const response1 = await api.fetchApi('/comfyui_manager/update_comfyui');
@ -240,7 +248,7 @@ async function updateAll(update_check_checkbox, manager_dialog) {
return false;
}
if(response1.status == 201 || response2.status == 201) {
app.ui.dialog.show("ComfyUI and all extensions have been updated to the latest version.<BR>To apply the updated custom node, please <button id='cm-reboot-button'><font size='3px'>RESTART</font></button> ComfyUI.");
app.ui.dialog.show("ComfyUI and all extensions have been updated to the latest version.<BR>To apply the updated custom node, please <button id='cm-reboot-button'><font size='3px'>RESTART</font></button> ComfyUI. And refresh browser.");
const rebootButton = document.getElementById('cm-reboot-button');
rebootButton.onclick = function() {
@ -253,8 +261,8 @@ async function updateAll(update_check_checkbox, manager_dialog) {
}
else {
app.ui.dialog.show('ComfyUI and all extensions are already up-to-date with the latest versions.');
app.ui.dialog.element.style.zIndex = 10010;
}
app.ui.dialog.element.style.zIndex = 10010;
}
return true;
}
@ -275,25 +283,25 @@ function newDOMTokenList(initialTokens) {
const classList = tmp.classList;
if (initialTokens) {
initialTokens.forEach(token => {
initialTokens.forEach(token => {
classList.add(token);
});
});
}
return classList;
}
}
/**
* Check whether the node is a potential output node (img, gif or video output)
*/
const isOutputNode = (node) => {
return [
"VHS_VideoCombine",
"PreviewImage",
"SaveImage",
"ADE_AnimateDiffCombine",
"SaveAnimatedWEBP",
].includes(node.type);
return [
"VHS_VideoCombine",
"PreviewImage",
"SaveImage",
"ADE_AnimateDiffCombine",
"SaveAnimatedWEBP",
].includes(node.type);
}
// -----------
@ -362,7 +370,7 @@ class ManagerMenuDialog extends ComfyDialog {
}
}),
$el("br", {}, []),
$el("br", {}, []),
update_all_button,
update_comfyui_button,
fetch_updates_button,
@ -454,37 +462,37 @@ class ManagerMenuDialog extends ComfyDialog {
}
});
// share
let share_combo = document.createElement("select");
const share_options = [
['none', 'None'],
['openart', 'OpenArt AI'],
['matrix', 'Matrix Server'],
['comfyworkflows', 'ComfyWorkflows'],
['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')
// share
let share_combo = document.createElement("select");
const share_options = [
['none', 'None'],
['openart', 'OpenArt AI'],
['matrix', 'Matrix Server'],
['comfyworkflows', 'ComfyWorkflows'],
['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.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";
}
});
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";
}
});
return [
$el("div", {}, [this.local_mode_checkbox, checkbox_text, this.update_check_checkbox, uc_checkbox_text]),
@ -682,13 +690,13 @@ app.registerExtension({
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;
}
if (share_option === 'openart') {
showOpenArtShareDialog();
return;
} else if (share_option === 'matrix' || share_option === 'comfyworkflows') {
showShareDialog(share_option);
return;
}
if(!ShareDialogChooser.instance) {
ShareDialogChooser.instance = new ShareDialogChooser();
@ -753,11 +761,11 @@ app.registerExtension({
return r;
};
this._addExtraNodeContextMenu(nodeType, app);
this._addExtraNodeContextMenu(nodeType, app);
},
async loadedGraphNode(node, app) {
if (node.has_errors) {
if (node.has_errors) {
const onDrawForeground = node.onDrawForeground;
node.onDrawForeground = function (ctx) {
const r = onDrawForeground?.apply?.(this, arguments);
@ -814,42 +822,42 @@ app.registerExtension({
},
_addExtraNodeContextMenu(node, app) {
const origGetExtraMenuOptions = node.prototype.getExtraMenuOptions;
node.prototype.getExtraMenuOptions = function (_, options) {
origGetExtraMenuOptions?.apply?.(this, arguments);
if (isOutputNode(node)) {
const { potential_outputs } = getPotentialOutputsAndOutputNodes([this]);
const hasOutput = potential_outputs.length > 0;
// Check if the previous menu option is `null`. If it's not,
// then we need to add a `null` as a separator.
if (options[options.length - 1] !== null) {
options.push(null);
}
options.push({
content: "🏞 Share Output",
disabled: !hasOutput,
const origGetExtraMenuOptions = node.prototype.getExtraMenuOptions;
node.prototype.getExtraMenuOptions = function (_, options) {
origGetExtraMenuOptions?.apply?.(this, arguments);
if (isOutputNode(node)) {
const { potential_outputs } = getPotentialOutputsAndOutputNodes([this]);
const hasOutput = potential_outputs.length > 0;
// Check if the previous menu option is `null`. If it's not,
// then we need to add a `null` as a separator.
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();
}
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);
}
}
}
},
});

2
js/common.js

@ -65,7 +65,7 @@ export async function install_checked_custom_node(grid_rows, target_i, caller, m
}
await caller.invalidateControl();
caller.updateMessage("<BR>To apply the installed/updated/disabled/enabled custom node, please <button id='cm-reboot-button'><font size='3px'>RESTART</font></button> ComfyUI.", 'cm-reboot-button');
caller.updateMessage("<BR>To apply the installed/updated/disabled/enabled custom node, please <button id='cm-reboot-button'><font size='3px'>RESTART</font></button> ComfyUI. And refresh browser.", 'cm-reboot-button');
}
};

248
js/custom-nodes-downloader.js

@ -259,89 +259,89 @@ export class CustomNodesInstaller extends ComfyDialog {
}
}
invalidate_checks(is_checked, install_state) {
if(is_checked) {
for(let i in this.grid_rows) {
let data = this.grid_rows[i].data;
let checkbox = this.grid_rows[i].checkbox;
let buttons = this.grid_rows[i].buttons;
checkbox.disabled = data.installed != install_state;
if(checkbox.disabled) {
for(let j in buttons) {
buttons[j].style.display = 'none';
}
}
else {
for(let j in buttons) {
buttons[j].style.display = null;
}
}
}
this.checkbox_all.disabled = false;
}
else {
for(let i in this.grid_rows) {
let checkbox = this.grid_rows[i].checkbox;
if(checkbox.check)
return; // do nothing
}
// every checkbox is unchecked -> enable all checkbox
for(let i in this.grid_rows) {
let checkbox = this.grid_rows[i].checkbox;
let buttons = this.grid_rows[i].buttons;
checkbox.disabled = false;
for(let j in buttons) {
buttons[j].style.display = null;
}
}
this.checkbox_all.checked = false;
this.checkbox_all.disabled = true;
}
}
check_all(is_checked) {
if(is_checked) {
// lookup first checked item's state
let check_state = null;
for(let i in this.grid_rows) {
let checkbox = this.grid_rows[i].checkbox;
if(checkbox.checked) {
check_state = this.grid_rows[i].data.installed;
}
}
if(check_state == null)
return;
// check only same state items
for(let i in this.grid_rows) {
let checkbox = this.grid_rows[i].checkbox;
if(this.grid_rows[i].data.installed == check_state)
checkbox.checked = true;
}
}
else {
// uncheck all
for(let i in this.grid_rows) {
let checkbox = this.grid_rows[i].checkbox;
let buttons = this.grid_rows[i].buttons;
checkbox.checked = false;
checkbox.disabled = false;
for(let j in buttons) {
buttons[j].style.display = null;
}
}
this.checkbox_all.disabled = true;
}
}
invalidate_checks(is_checked, install_state) {
if(is_checked) {
for(let i in this.grid_rows) {
let data = this.grid_rows[i].data;
let checkbox = this.grid_rows[i].checkbox;
let buttons = this.grid_rows[i].buttons;
checkbox.disabled = data.installed != install_state;
if(checkbox.disabled) {
for(let j in buttons) {
buttons[j].style.display = 'none';
}
}
else {
for(let j in buttons) {
buttons[j].style.display = null;
}
}
}
this.checkbox_all.disabled = false;
}
else {
for(let i in this.grid_rows) {
let checkbox = this.grid_rows[i].checkbox;
if(checkbox.check)
return; // do nothing
}
// every checkbox is unchecked -> enable all checkbox
for(let i in this.grid_rows) {
let checkbox = this.grid_rows[i].checkbox;
let buttons = this.grid_rows[i].buttons;
checkbox.disabled = false;
for(let j in buttons) {
buttons[j].style.display = null;
}
}
this.checkbox_all.checked = false;
this.checkbox_all.disabled = true;
}
}
check_all(is_checked) {
if(is_checked) {
// lookup first checked item's state
let check_state = null;
for(let i in this.grid_rows) {
let checkbox = this.grid_rows[i].checkbox;
if(checkbox.checked) {
check_state = this.grid_rows[i].data.installed;
}
}
if(check_state == null)
return;
// check only same state items
for(let i in this.grid_rows) {
let checkbox = this.grid_rows[i].checkbox;
if(this.grid_rows[i].data.installed == check_state)
checkbox.checked = true;
}
}
else {
// uncheck all
for(let i in this.grid_rows) {
let checkbox = this.grid_rows[i].checkbox;
let buttons = this.grid_rows[i].buttons;
checkbox.checked = false;
checkbox.disabled = false;
for(let j in buttons) {
buttons[j].style.display = null;
}
}
this.checkbox_all.disabled = true;
}
}
async createGrid() {
var grid = document.createElement('table');
@ -349,24 +349,24 @@ export class CustomNodesInstaller extends ComfyDialog {
this.grid_rows = {};
let self = this;
let self = this;
var thead = document.createElement('thead');
var tbody = document.createElement('tbody');
var thead = document.createElement('thead');
var tbody = document.createElement('tbody');
var headerRow = document.createElement('tr');
thead.style.position = "sticky";
thead.style.top = "0px";
thead.style.borderCollapse = "collapse";
thead.style.tableLayout = "fixed";
thead.style.borderCollapse = "collapse";
thead.style.tableLayout = "fixed";
var header0 = document.createElement('th');
header0.style.width = "20px";
this.checkbox_all = $el("input",{type:'checkbox', id:'check_all'},[]);
header0.appendChild(this.checkbox_all);
this.checkbox_all.checked = false;
this.checkbox_all.disabled = true;
this.checkbox_all.addEventListener('change', function() { self.check_all.call(self, self.checkbox_all.checked); });
this.checkbox_all = $el("input",{type:'checkbox', id:'check_all'},[]);
header0.appendChild(this.checkbox_all);
this.checkbox_all.checked = false;
this.checkbox_all.disabled = true;
this.checkbox_all.addEventListener('change', function() { self.check_all.call(self, self.checkbox_all.checked); });
var header1 = document.createElement('th');
header1.innerHTML = '&nbsp;&nbsp;ID&nbsp;&nbsp;';
@ -380,7 +380,7 @@ export class CustomNodesInstaller extends ComfyDialog {
var header4 = document.createElement('th');
header4.innerHTML = 'Description';
header4.style.width = "60%";
// header4.classList.add('expandable-column');
// header4.classList.add('expandable-column');
var header5 = document.createElement('th');
header5.innerHTML = 'Install';
header5.style.width = "130px";
@ -398,7 +398,7 @@ export class CustomNodesInstaller extends ComfyDialog {
header5.style.position = "sticky";
header5.style.top = "0px";
thead.appendChild(headerRow);
thead.appendChild(headerRow);
headerRow.appendChild(header0);
headerRow.appendChild(header1);
headerRow.appendChild(header2);
@ -421,28 +421,28 @@ export class CustomNodesInstaller extends ComfyDialog {
let dataRow = document.createElement('tr');
let data0 = document.createElement('td');
let checkbox = $el("input",{type:'checkbox', id:`check_${i}`},[]);
data0.appendChild(checkbox);
checkbox.checked = false;
checkbox.addEventListener('change', function() { self.invalidate_checks.call(self, checkbox.checked, data.installed); });
let checkbox = $el("input",{type:'checkbox', id:`check_${i}`},[]);
data0.appendChild(checkbox);
checkbox.checked = false;
checkbox.addEventListener('change', function() { self.invalidate_checks.call(self, checkbox.checked, data.installed); });
var data1 = document.createElement('td');
data1.style.textAlign = "center";
data1.innerHTML = i+1;
var data2 = document.createElement('td');
data2.style.maxWidth = "100px";
data2.style.maxWidth = "100px";
data2.className = "cm-node-author"
data2.textContent = ` ${data.author}`;
data2.style.whiteSpace = "nowrap";
data2.style.overflow = "hidden";
data2.style.overflow = "hidden";
data2.style.textOverflow = "ellipsis";
var data3 = document.createElement('td');
data3.style.maxWidth = "200px";
data3.style.wordWrap = "break-word";
var data3 = document.createElement('td');
data3.style.maxWidth = "200px";
data3.style.wordWrap = "break-word";
data3.className = "cm-node-name"
data3.innerHTML = `&nbsp;<a href=${data.reference} target="_blank"><font color="skyblue"><b>${data.title}</b></font></a>`;
data3.innerHTML = `&nbsp;<a href=${data.reference} target="_blank"><font color="skyblue"><b>${data.title}</b></font></a>`;
if(data.installed == 'Fail')
data3.innerHTML = '&nbsp;<font color="BLACK"><B>(IMPORT FAILED)</B></font>' + data3.innerHTML;
@ -452,7 +452,7 @@ export class CustomNodesInstaller extends ComfyDialog {
let conflicts = this.conflict_mappings[data.files[0]];
if(conflicts) {
let buf = '<BR><BR><FONT color="#AA3333"><B>Conflicted Nodes:</B><BR>';
let buf = '<p class="cm-conflicted-nodes-text"><B><font color="BLACK">Conflicted Nodes:</FONT></B><BR>';
for(let k in conflicts) {
let node_name = conflicts[k][0];
@ -464,13 +464,13 @@ export class CustomNodesInstaller extends ComfyDialog {
extension_name = extension_name.slice(0, -4);
}
buf += `${node_name} [${extension_name}], `;
buf += `<B>${node_name}</B> [${extension_name}], `;
}
if(buf.endsWith(', ')) {
buf = buf.slice(0, -2);
}
buf += "</FONT>";
buf += "</p>";
data4.innerHTML += buf;
}
@ -537,7 +537,7 @@ export class CustomNodesInstaller extends ComfyDialog {
installBtn.style.color = 'white';
}
let j = i;
let j = i;
if(installBtn2 != null) {
installBtn2.style.width = "120px";
installBtn2.addEventListener('click', function() {
@ -587,28 +587,28 @@ export class CustomNodesInstaller extends ComfyDialog {
let buttons = [];
if(installBtn) {
buttons.push(installBtn);
}
buttons.push(installBtn);
}
if(installBtn2) {
buttons.push(installBtn2);
}
buttons.push(installBtn2);
}
if(installBtn3) {
buttons.push(installBtn3);
}
buttons.push(installBtn3);
}
this.grid_rows[i] = {data:data, buttons:buttons, checkbox:checkbox, control:dataRow};
}
const panel = document.createElement('div');
panel.style.width = "100%";
panel.style.width = "100%";
panel.appendChild(grid);
function handleResize() {
const parentHeight = self.element.clientHeight;
const gridHeight = parentHeight - 200;
function handleResize() {
const parentHeight = self.element.clientHeight;
const gridHeight = parentHeight - 200;
grid.style.height = gridHeight + "px";
}
grid.style.height = gridHeight + "px";
}
window.addEventListener("resize", handleResize);
grid.style.position = "relative";
@ -620,7 +620,7 @@ export class CustomNodesInstaller extends ComfyDialog {
this.element.style.width = "80%";
this.element.appendChild(panel);
handleResize();
handleResize();
}
createFilterCombo() {
@ -658,8 +658,8 @@ export class CustomNodesInstaller extends ComfyDialog {
self.apply_searchbox();
});
if(self.filter) {
combo.value = self.filter;
if(self.filter) {
combo.value = self.filter;
}
return combo;

2
js/snapshot.js

@ -23,7 +23,7 @@ async function restore_snapshot(target) {
}
finally {
await SnapshotManager.instance.invalidateControl();
SnapshotManager.instance.updateMessage("<BR>To apply the snapshot, please <button id='cm-reboot-button'><font size='3px'>RESTART</font></button> ComfyUI.", 'cm-reboot-button');
SnapshotManager.instance.updateMessage("<BR>To apply the snapshot, please <button id='cm-reboot-button'><font size='3px'>RESTART</font></button> ComfyUI. And refresh browser.", 'cm-reboot-button');
}
}
}

11
prestartup_script.py

@ -173,11 +173,18 @@ try:
def reconfigure(self, *args, **kwargs):
pass
# You can close through sys.stderr.close_log()
def close_log(self):
sys.stderr = original_stderr
sys.stdout = original_stdout
log_file.close()
def close_log():
sys.stderr = original_stderr
sys.stdout = original_stdout
log_file.close()
sys.stdout = ComfyUIManagerLogger(True)
sys.stderr = ComfyUIManagerLogger(False)

Loading…
Cancel
Save