Drag&drop for unfinished tasks hooks up the workflow JSON. Updated readme

This commit is contained in:
M0rtus59
2026-07-19 12:26:17 +05:00
parent 5fde92b51a
commit c2c82065a7
5 changed files with 53 additions and 29 deletions
+4 -2
View File
@@ -14,7 +14,7 @@ A lightweight, high-performance ComfyUI extension that replaces the cluttered st
* A compact topbar layout displaying both workflow tabs and the control panel on a single unified top bar. See the 'Comfy Layout' toggle in the settings.
* Toggles to hide buttons you don't need from the side panel.
* **[NEW]** Preview compare slider - just click the result image preview in the sidebar, and then `Shift+Click` another to load it alongside the first one for pixel by pixel comparison.
* **[NEW]** Prevent certain nodes from showing the output in the queue bar and intermediate results. `Ctrl+Q` to toggle.
* **[NEW]** Prevent selected nodes from showing the output in the queue bar and intermediate results. `Ctrl+Q` to toggle.
<img width="385" height="336" alt="image" src="https://github.com/user-attachments/assets/743fbf85-9281-4561-9dd0-cd9af4d8c0e4" />
@@ -33,8 +33,10 @@ Restart your ComfyUI server and refresh the browser tab.
## ⚙️ Configuration
Additional tweaks are seamlessly integrated into the standard ComfyUI Settings panel. From there, you can adjust thresholds or fully replace the stock V2 panel by enabling options like **"Override Stock Job History Tab"**.
See additional tweaks in ComfyUI settings menu > Comfy Sidebar. From there, you can adjust the layout or fully replace the stock V2 panel by enabling options like **"Comfy Layout"** and **"Replace the stock Job History sidebar with Comfy Queue"**.
## ⌨️ Shortcuts
* **`Q`**: Instantly toggles the sidebar panel open or closed. Safely ignores inputs if you are currently typing inside a text field, input area, or combo box.
* **`Ctrl+Q on a selected node`**: Sets the node to be ignored in the sidebar panel results.
* **`Click`** on a card to enter preview. **`Shift+Click`** on another card in preview to enter compare mode.
+8
View File
@@ -1,4 +1,5 @@
import { app } from "/scripts/app.js";
import { State } from "./state.js";
async function uploadDroppedImageToInput(imageObj) {
const src = `/view?filename=${encodeURIComponent(imageObj.filename)}&type=${imageObj.type || 'output'}&subfolder=${encodeURIComponent(imageObj.subfolder || '')}`;
@@ -26,6 +27,13 @@ export function setupDragAndDrop() {
});
document.addEventListener("drop", async (e) => {
// Cancel loading entirely if dropping inside the sidebar area
const isSidebarDrop = e.target.closest('.comfyui-sidebar, .comfy-sidebar, [class*="sidebar"]') ||
(State.sidebarContainer && State.sidebarContainer.contains(e.target));
if (isSidebarDrop) {
return;
}
const canvas = app.canvas;
if (!canvas || !canvas.graph) return;
+7 -4
View File
@@ -1,6 +1,6 @@
import { app } from "/scripts/app.js";
import { api } from "/scripts/api.js";
import { State, promptStates, pruneHistory, loadStatesFromLocalStorage } from "./state.js";
import { State, promptStates, pruneHistory, loadStatesFromLocalStorage, cardElements } from "./state.js";
import { findImagesInOutputs, findTextsInOutputs } from "./utils.js";
export let renderDOMFn = () => {};
@@ -203,11 +203,14 @@ export async function initSessionAndHistory() {
}
const storedSessionId = localStorage.getItem("comfy_sidebar_backend_session_id");
if (backendSessionId && backendSessionId === storedSessionId) {
loadStatesFromLocalStorage();
} else {
if (backendSessionId && backendSessionId !== storedSessionId) {
// Session changed (server restarted)! Clear cached memory.
promptStates.clear();
cardElements.clear();
localStorage.removeItem("comfy_sidebar_prompt_states");
if (backendSessionId) localStorage.setItem("comfy_sidebar_backend_session_id", backendSessionId);
} else if (!storedSessionId && backendSessionId) {
localStorage.setItem("comfy_sidebar_backend_session_id", backendSessionId);
}
const historyData = await api.getHistory();
+4 -1
View File
@@ -66,4 +66,7 @@ export function loadStatesFromLocalStorage() {
} catch (e) {
console.error("Comfy Sidebar: Failed to load state from localStorage", e);
}
}
}
// Load instantly and synchronously on script import to prevent race conditions during early renders!
loadStatesFromLocalStorage();
+30 -22
View File
@@ -367,26 +367,32 @@ function renderCardImages(cardObj, state, keepAspect) {
mediaEl.onmouseenter = () => { playIcon.style.opacity = "0"; mediaEl.play().catch(()=>{}); };
mediaEl.onmouseleave = () => { playIcon.style.opacity = "1"; mediaEl.pause(); };
} else {
mediaEl.setAttribute("draggable", "true");
mediaEl.onload = () => {
applyDimensions(mediaEl.naturalWidth, mediaEl.naturalHeight);
};
const isUnfinished = state.status && state.status !== "completed";
if (isUnfinished) {
mediaEl.setAttribute("draggable", "false");
mediaEl.style.cursor = "grab";
mediaEl.removeEventListener("dragstart", mediaEl._currentDragStart);
delete mediaEl._currentDragStart;
} else {
mediaEl.setAttribute("draggable", "true");
mediaEl.style.cursor = "zoom-in";
const dragStartHandler = (e) => {
State.currentDraggedImgData = { ...img, workflow: state.workflow };
try {
e.dataTransfer.setData("text/uri-list", src);
e.dataTransfer.setData("text/plain", src);
} catch (err) {}
e.dataTransfer.effectAllowed = "copy";
e.stopPropagation();
};
mediaEl.removeEventListener("dragstart", mediaEl._currentDragStart);
mediaEl.addEventListener("dragstart", dragStartHandler);
mediaEl._currentDragStart = dragStartHandler;
}
const playIcon = wrapper.querySelector(".comfy-sidebar-play-icon");
if (playIcon) playIcon.remove();
const dragStartHandler = (e) => {
State.currentDraggedImgData = { ...img, workflow: state.workflow };
try {
e.dataTransfer.setData("text/uri-list", src);
e.dataTransfer.setData("text/plain", src);
} catch (err) {}
e.dataTransfer.effectAllowed = "copy";
e.stopPropagation();
};
mediaEl.removeEventListener("dragstart", mediaEl._currentDragStart);
mediaEl.addEventListener("dragstart", dragStartHandler);
mediaEl._currentDragStart = dragStartHandler;
}
// Smooth in-memory source swapping for blob live previews
@@ -924,9 +930,10 @@ export function renderDOM() {
});
card.addEventListener("dragstart", (e) => {
// Custom dragstart is only used for JSON-only workflows to supply a local DownloadURL.
// For image cards, dragging is handled natively by the browser on the child <img> tag.
if (state.workflow && (!state.images || state.images.length === 0)) {
// Custom dragstart is used for JSON-only or unfinished workflows to supply a local DownloadURL.
// For completed image cards, dragging is handled natively by the browser on the child <img> tag.
const isUnfinished = state.status && state.status !== "completed";
if (state.workflow && (!state.images || state.images.length === 0 || isUnfinished)) {
if (cardObj.firstImgElement) e.dataTransfer.setDragImage(cardObj.firstImgElement, 15, 15);
const jsonStr = JSON.stringify(state.workflow, null, 2);
try {
@@ -943,9 +950,10 @@ export function renderDOM() {
cardObj.element.className = `comfy-sidebar-card ${state.status}`;
// Native drag isolation: completely remove draggable flags on image containers.
// Native drag isolation: completely remove draggable flags on image containers for finished cards.
// This exposes the child <img> tag directly to Chrome's native filesystem drag APIs.
if (state.images && state.images.length > 0) {
const isUnfinished = state.status && state.status !== "completed";
if (state.images && state.images.length > 0 && !isUnfinished) {
cardObj.element.removeAttribute("draggable");
} else {
cardObj.element.setAttribute("draggable", "true");