mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 07:05:43 -03:00
feat: refactor LoRA manager widget into top menu extension
- Rename ui_utils.js to top_menu_extension.js to better reflect functionality - Replace custom button creation with ComfyUI Button and ButtonGroup components - Implement proper top menu integration using ComfyUI's menu system - Simplify window opening logic with shift-click support for new windows - Add retry mechanism for attaching button to menu - Improve code organization and maintainability by leveraging existing UI components
This commit is contained in:
@@ -1,147 +1,104 @@
|
|||||||
import { app } from "../../scripts/app.js";
|
import { app } from "../../scripts/app.js";
|
||||||
const extension = {
|
import { ComfyButtonGroup } from "../../scripts/ui/components/buttonGroup.js";
|
||||||
name: "lora-manager.widget",
|
import { ComfyButton } from "../../scripts/ui/components/button.js";
|
||||||
};
|
|
||||||
|
|
||||||
app.registerExtension(extension);
|
const BUTTON_GROUP_CLASS = "lora-manager-top-menu-group";
|
||||||
const config = {
|
const BUTTON_TOOLTIP = "Launch LoRA Manager (Shift+Click opens in new window)";
|
||||||
newTab: true,
|
const LORA_MANAGER_PATH = "/loras";
|
||||||
newWindow: {
|
const NEW_WINDOW_FEATURES = "width=1200,height=800,resizable=yes,scrollbars=yes,status=yes";
|
||||||
width: 1200,
|
const MAX_ATTACH_ATTEMPTS = 120;
|
||||||
height: 800,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const createWidget = ({ className, text, tooltip, includeIcon, svgMarkup }) => {
|
const openLoraManager = (event) => {
|
||||||
const button = document.createElement('button');
|
const url = `${window.location.origin}${LORA_MANAGER_PATH}`;
|
||||||
button.className = className;
|
|
||||||
button.setAttribute('aria-label', tooltip);
|
|
||||||
button.title = tooltip;
|
|
||||||
|
|
||||||
if (includeIcon && svgMarkup) {
|
if (event.shiftKey) {
|
||||||
const iconContainer = document.createElement('span');
|
window.open(url, "_blank", NEW_WINDOW_FEATURES);
|
||||||
iconContainer.innerHTML = svgMarkup;
|
|
||||||
iconContainer.style.display = 'flex';
|
|
||||||
iconContainer.style.alignItems = 'center';
|
|
||||||
iconContainer.style.justifyContent = 'center';
|
|
||||||
iconContainer.style.width = '20px';
|
|
||||||
iconContainer.style.height = '16px';
|
|
||||||
button.appendChild(iconContainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
const textNode = document.createTextNode(text);
|
|
||||||
button.appendChild(textNode);
|
|
||||||
|
|
||||||
button.addEventListener('click', onClick);
|
|
||||||
return button;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onClick = (e) => {
|
|
||||||
const loraManagerUrl = `${window.location.origin}/loras`;
|
|
||||||
|
|
||||||
// Check if Shift key is pressed to determine how to open
|
|
||||||
if (e.shiftKey) {
|
|
||||||
// Open in new window
|
|
||||||
const { width, height } = config.newWindow;
|
|
||||||
const windowFeatures = `width=${width},height=${height},resizable=yes,scrollbars=yes,status=yes`;
|
|
||||||
window.open(loraManagerUrl, '_blank', windowFeatures);
|
|
||||||
} else {
|
|
||||||
// Default behavior: open in new tab
|
|
||||||
window.open(loraManagerUrl, '_blank');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const addWidgetMenuRight = (menuRight) => {
|
|
||||||
let buttonGroup = menuRight.querySelector('.comfyui-button-group');
|
|
||||||
|
|
||||||
if (!buttonGroup) {
|
|
||||||
buttonGroup = document.createElement('div');
|
|
||||||
buttonGroup.className = 'comfyui-button-group';
|
|
||||||
menuRight.appendChild(buttonGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
const loraManagerButton = createWidget({
|
|
||||||
className: 'comfyui-button comfyui-menu-mobile-collapse primary',
|
|
||||||
text: '',
|
|
||||||
tooltip: 'Launch Lora Manager (Shift+Click to open in new window)',
|
|
||||||
includeIcon: true,
|
|
||||||
svgMarkup: getLoraManagerIcon(),
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonGroup.appendChild(loraManagerButton);
|
|
||||||
};
|
|
||||||
|
|
||||||
const addWidgetMenu = (menu) => {
|
|
||||||
const resetViewButton = menu.querySelector('#comfy-reset-view-button');
|
|
||||||
if (!resetViewButton) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const loraManagerButton = createWidget({
|
window.open(url, "_blank");
|
||||||
className: 'comfy-lora-manager-button',
|
|
||||||
text: 'Lora Manager',
|
|
||||||
tooltip: 'Launch Lora Manager (Shift+Click to open in new window)',
|
|
||||||
includeIcon: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
resetViewButton.insertAdjacentElement('afterend', loraManagerButton);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const addWidget = (selector, callback) => {
|
const createTopMenuButton = () => {
|
||||||
const observer = new MutationObserver((mutations, obs) => {
|
const button = new ComfyButton({
|
||||||
const element = document.querySelector(selector);
|
icon: "loramanager",
|
||||||
if (element) {
|
tooltip: BUTTON_TOOLTIP,
|
||||||
callback(element);
|
app,
|
||||||
obs.disconnect();
|
enabled: true,
|
||||||
|
classList: "comfyui-button comfyui-menu-mobile-collapse primary",
|
||||||
|
});
|
||||||
|
|
||||||
|
button.element.setAttribute("aria-label", BUTTON_TOOLTIP);
|
||||||
|
button.element.title = BUTTON_TOOLTIP;
|
||||||
|
|
||||||
|
if (button.iconElement) {
|
||||||
|
button.iconElement.innerHTML = getLoraManagerIcon();
|
||||||
|
button.iconElement.style.width = "1.2rem";
|
||||||
|
button.iconElement.style.height = "1.2rem";
|
||||||
|
}
|
||||||
|
|
||||||
|
button.element.addEventListener("click", openLoraManager);
|
||||||
|
return button;
|
||||||
|
};
|
||||||
|
|
||||||
|
const attachTopMenuButton = (attempt = 0) => {
|
||||||
|
if (document.querySelector(`.${BUTTON_GROUP_CLASS}`)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const settingsGroup = app.menu?.settingsGroup;
|
||||||
|
if (!settingsGroup?.element?.parentElement) {
|
||||||
|
if (attempt >= MAX_ATTACH_ATTEMPTS) {
|
||||||
|
console.warn("LoRA Manager: unable to locate the ComfyUI settings button group.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
observer.observe(document.body, { childList: true, subtree: true });
|
requestAnimationFrame(() => attachTopMenuButton(attempt + 1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loraManagerButton = createTopMenuButton();
|
||||||
|
const buttonGroup = new ComfyButtonGroup(loraManagerButton);
|
||||||
|
buttonGroup.element.classList.add(BUTTON_GROUP_CLASS);
|
||||||
|
|
||||||
|
settingsGroup.element.before(buttonGroup.element);
|
||||||
};
|
};
|
||||||
|
|
||||||
const initializeWidgets = () => {
|
|
||||||
addWidget('.comfyui-menu-right', addWidgetMenuRight);
|
|
||||||
addWidget('.comfy-menu', addWidgetMenu);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Fetch version info from the API
|
|
||||||
const fetchVersionInfo = async () => {
|
const fetchVersionInfo = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/lm/version-info');
|
const response = await fetch("/api/lm/version-info");
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
return data.version;
|
return data.version;
|
||||||
}
|
}
|
||||||
return '';
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching version info:', error);
|
console.error("LoRA Manager: error fetching version info:", error);
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
};
|
};
|
||||||
|
|
||||||
// Register about badge with version info
|
const createAboutBadge = (version) => {
|
||||||
const registerAboutBadge = async () => {
|
const label = version ? `LoRA Manager v${version}` : "LoRA Manager";
|
||||||
let version = await fetchVersionInfo();
|
|
||||||
const label = version ? `LoRA-Manager v${version}` : 'LoRA-Manager';
|
return {
|
||||||
|
label,
|
||||||
app.registerExtension({
|
url: "https://github.com/willmiao/ComfyUI-Lora-Manager",
|
||||||
name: 'LoraManager.AboutBadge',
|
icon: "pi pi-tags",
|
||||||
aboutPageBadges: [
|
};
|
||||||
{
|
|
||||||
label: label,
|
|
||||||
url: 'https://github.com/willmiao/ComfyUI-Lora-Manager',
|
|
||||||
icon: 'pi pi-tags'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize everything
|
app.registerExtension({
|
||||||
const initialize = () => {
|
name: "LoraManager.TopMenu",
|
||||||
initializeWidgets();
|
aboutPageBadges: [createAboutBadge()],
|
||||||
registerAboutBadge();
|
async setup() {
|
||||||
};
|
attachTopMenuButton();
|
||||||
|
|
||||||
|
const version = await fetchVersionInfo();
|
||||||
|
this.aboutPageBadges = [createAboutBadge(version)];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const getLoraManagerIcon = () => {
|
const getLoraManagerIcon = () => {
|
||||||
return `
|
return `
|
||||||
@@ -182,5 +139,3 @@ const getLoraManagerIcon = () => {
|
|||||||
</svg>
|
</svg>
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|
||||||
initialize();
|
|
||||||
Reference in New Issue
Block a user