import { app } from "/scripts/app.js"; export function findOriginalPropertiesButton() { const byTestId = document.querySelector('[data-testid="properties-panel-toggle"]'); if (byTestId && !byTestId.classList.contains("comfy-sidebar-custom-properties-toggle")) { return byTestId; } const icons = document.querySelectorAll('[class*="lucide--panel-right"], [class*="lucide--panel-left"], [class*="lucide--panel-bottom"]'); for (const icon of icons) { const btn = icon.closest('button, [role="button"], .comfyui-menu-item, .p-button'); if (btn && !btn.classList.contains("comfy-sidebar-custom-properties-toggle")) { return btn; } } const buttons = document.querySelectorAll('button, [role="button"], .p-button'); for (const btn of buttons) { if (btn.classList.contains("comfy-sidebar-custom-properties-toggle")) continue; const title = (btn.getAttribute("title") || btn.getAttribute("aria-label") || "").toLowerCase(); if (title.includes("workflow overview") || title.includes("properties") || title.includes("toggle panel")) { return btn; } } return null; } export function findTopbarContainer() { const container = document.querySelector('[data-testid="action-bar-buttons"], [class*="actionbar-buttons"], .actionbar-buttons, [class*="actionbar"]'); if (container) return container; const orig = findOriginalPropertiesButton(); if (orig?.parentNode) return orig.parentNode; const buttons = document.querySelectorAll("button, .p-button"); for (const btn of buttons) { if (btn.classList.contains("comfy-sidebar-custom-properties-toggle")) continue; const title = (btn.getAttribute("title") || btn.getAttribute("aria-label") || "").toLowerCase(); if (title.includes("run") || title.includes("manager")) { if (btn.parentNode) return btn.parentNode; } } return null; } export function isPropertiesPanelOpen() { const panel = document.querySelector('[data-testid="properties-panel"]'); if (panel && panel.offsetWidth > 0 && panel.offsetHeight > 0) return true; const headings = document.querySelectorAll('h1, h2, h3, h4'); for (const h of headings) { if (h.textContent.trim() === "Workflow Overview" && h.offsetWidth > 0 && h.offsetHeight > 0) return true; } const origBtn = findOriginalPropertiesButton(); if (origBtn) { if (origBtn.classList.contains("p-button-active") || origBtn.classList.contains("active") || origBtn.getAttribute("aria-expanded") === "true" || origBtn.getAttribute("aria-pressed") === "true") { return true; } } return false; } export function findActiveQueueIndicator() { const container = findTopbarContainer(); if (!container) return null; const buttons = container.querySelectorAll("button, .p-button, .comfyui-menu-item"); for (const btn of buttons) { if (btn.classList.contains("comfy-sidebar-custom-properties-toggle")) continue; const text = (btn.textContent || "").toLowerCase(); if (text.includes("active") || text.includes("queued") || text.includes("running") || text.includes("pending")) { return btn; } } return null; } export function findNativeExtensionsPanel() { return Array.from(document.querySelectorAll('.shadow-interface:not(.actionbar-container)')) .find(el => el.textContent.toLowerCase().includes('extensions') || el.querySelector('button')?.textContent.toLowerCase().includes('extensions')); } export function findGraphButton() { const elements = document.querySelectorAll('.p-1.bg-base-background.rounded-lg, .bg-base-background.rounded-lg, .bg-secondary-background.rounded-lg.items-center.inline-flex.pointer-events-auto, [data-testid="graph-view-button"]'); for (const el of elements) { if (el.closest('.p-dialog, .comfy-modal, [role="dialog"], .p-sidebar, .comfy-settings, .comfyui-sidebar, .comfy-sidebar')) continue; return el.closest('.group, .p-1') || el; } const fallbacks = document.querySelectorAll('button, .bg-base-background, .bg-secondary-background'); for (const el of fallbacks) { if (el.closest('.p-dialog, .comfy-modal, [role="dialog"], .p-sidebar, .comfy-settings, .comfyui-sidebar, .comfy-sidebar')) continue; const text = (el.textContent || el.getAttribute("title") || el.getAttribute("aria-label") || "").toLowerCase(); if (text.includes("graph") || text.includes("workflow") || el.querySelector('[class*="sitemap"], [class*="workflow"]')) { return el.closest('.group, .p-1, .bg-base-background, .bg-secondary-background') || el; } } return null; } export function findOurSidebarButton() { const icon = document.querySelector('.pi-images'); return icon ? icon.closest('.comfyui-sidebar-tab, button, [role="tab"]') : null; } export function findStandardQueueButton() { for (const iconSelector of [".pi-history", ".pi-clock", ".pi-server", ".pi-list", ".pi-sliders-h"]) { const icon = document.querySelector(iconSelector); if (icon) { const btn = icon.closest('.comfyui-sidebar-tab, button, [role="tab"]'); if (btn && !btn.querySelector('.pi-images')) return btn; } } const buttons = document.querySelectorAll('.comfyui-sidebar-tab, button, [role="tab"]'); for (const btn of buttons) { const title = btn.title || btn.getAttribute('aria-label') || ''; if ((title.toLowerCase().includes('queue') || title.toLowerCase().includes('history')) && !btn.querySelector('.pi-images') && !btn.id?.includes('classic-comfy-sidebar')) { return btn; } } return null; } export function updateSidebarBadge(count) { const icons = document.querySelectorAll('.pi-images'); icons.forEach(icon => { const btn = icon.closest('.comfyui-sidebar-tab, button, [role="tab"]'); if (btn) { let badge = btn.querySelector('.comfy-sidebar-badge'); if (count > 0) { if (!badge) { btn.style.position = 'relative'; badge = document.createElement('div'); badge.className = 'comfy-sidebar-badge'; Object.assign(badge.style, { position: 'absolute', top: '2px', right: '2px', background: '#0ea5e9', color: '#fff', borderRadius: '50%', width: '16px', height: '16px', fontSize: '10px', display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 'bold', pointerEvents: 'none' }); btn.appendChild(badge); } badge.textContent = count > 99 ? '99+' : count; } else if (badge) { badge.remove(); } } }); } export function applySidebarOverride() { const overrideStock = app.ui.settings?.getSettingValue?.("Comfy Sidebar.Hide Junk.Override Stock Job History Tab") ?? false; const stdBtn = findStandardQueueButton(); const ourBtn = findOurSidebarButton(); if (stdBtn) { if (!stdBtn._originalDisplay) { stdBtn._originalDisplay = window.getComputedStyle(stdBtn).display || "block"; } if (overrideStock) { stdBtn.style.setProperty("display", "none", "important"); if (!stdBtn._overrideClickListener) { stdBtn._overrideClickListener = (e) => { e.preventDefault(); e.stopPropagation(); const b = findOurSidebarButton(); if (b) b.click(); }; stdBtn.addEventListener('click', stdBtn._overrideClickListener, true); } if (ourBtn && stdBtn.parentNode && ourBtn.nextSibling !== stdBtn) { stdBtn.parentNode.insertBefore(ourBtn, stdBtn); } } else { stdBtn.style.setProperty("display", stdBtn._originalDisplay === "none" ? "block" : stdBtn._originalDisplay); if (stdBtn._overrideClickListener) { stdBtn.removeEventListener('click', stdBtn._overrideClickListener, true); stdBtn._overrideClickListener = null; } if (ourBtn && stdBtn.parentNode && ourBtn.parentNode === stdBtn.parentNode && ourBtn !== stdBtn.parentNode.lastChild) { stdBtn.parentNode.appendChild(ourBtn); } } } } export function centerAndSelectCanvasNode(nodeId) { if (!app.graph || !app.canvas) return false; const id = typeof nodeId === "string" ? Number(nodeId) : nodeId; const node = app.graph.getNodeById ? (app.graph.getNodeById(id) || app.graph.getNodeById(String(nodeId))) : null; if (node) { if (app.canvas.centerOnNode) app.canvas.centerOnNode(node); if (app.canvas.selectNode) app.canvas.selectNode(node); return true; } return false; }