From 40c7eaa7ced85eaeb4839e1e6a333cfd498a6004 Mon Sep 17 00:00:00 2001 From: space-nuko <24979496+space-nuko@users.noreply.github.com> Date: Mon, 22 May 2023 14:16:31 -0500 Subject: [PATCH] Delete queue/history item --- src/lib/api.ts | 2 +- src/lib/components/ComfyApp.ts | 28 +++++++++++ src/lib/components/ComfyQueue.svelte | 35 ++++++++----- .../components/ComfyQueueListDisplay.svelte | 37 +++++++++++++- src/lib/stores/queueState.ts | 49 ++++++++++++++++++- 5 files changed, 136 insertions(+), 15 deletions(-) diff --git a/src/lib/api.ts b/src/lib/api.ts index 3c1f413..df384ad 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -331,7 +331,7 @@ export default class ComfyAPI { * @param {string} type The type of item to delete, queue or history * @param {number} id The id of the item to delete */ - async deleteItem(type: QueueItemType, id: number): Promise { + async deleteItem(type: QueueItemType, id: PromptID): Promise { return this.postItem(type, { delete: [id] }); } diff --git a/src/lib/components/ComfyApp.ts b/src/lib/components/ComfyApp.ts index 95e04f9..deb2166 100644 --- a/src/lib/components/ComfyApp.ts +++ b/src/lib/components/ComfyApp.ts @@ -509,7 +509,35 @@ export default class ComfyApp { this.api.init(); } + async interrupt() { + if (get(queueState).isInterrupting) + return + + queueState.update(s => { s.isInterrupting = true; return s; }) + await this.api.interrupt() + .finally(() => { + queueState.update(s => { s.isInterrupting = true; return s }) + }); + } + + async deleteQueueItem(type: QueueItemType, promptID: PromptID) { + if (get(queueState).isInterrupting) + return + + queueState.update(s => { s.isInterrupting = true; return s; }) + await this.api.deleteItem(type, promptID) + .then(() => { + queueState.queueItemDeleted(type, promptID); + }) + .finally(() => { + queueState.update(s => { s.isInterrupting = false; return s; }) + }); + } + async clearQueue(type: QueueItemType) { + if (get(queueState).isInterrupting) + return + queueState.update(s => { s.isInterrupting = true; return s; }) await this.api.clearItems(type) .then(() => { diff --git a/src/lib/components/ComfyQueue.svelte b/src/lib/components/ComfyQueue.svelte index 8cb5304..7c445c9 100644 --- a/src/lib/components/ComfyQueue.svelte +++ b/src/lib/components/ComfyQueue.svelte @@ -85,6 +85,27 @@ changed = false; } + async function deleteEntry(entry: QueueUIEntry, event: MouseEvent) { + event.preventDefault(); + event.stopImmediatePropagation() + + // TODO support interrupting from multiple running items! + if (entry.status === "running") { + await app.interrupt(); + } + else { + await app.deleteQueueItem(mode, entry.entry.promptID); + } + + if (mode === "queue") { + _queuedEntries = [] + _runningEntries = [] + } + + _entries = []; + changed = true; + } + async function clearQueue() { await app.clearQueue(mode); @@ -188,17 +209,7 @@ } async function interrupt() { - if ($queueState.isInterrupting) - return - - const app = (window as any).app as ComfyApp; - if (!app || !app.api) - return; - - await app.api.interrupt() - .then(() => { - queueState.update(s => { s.isInterrupting = true; return s }) - }); + await app.interrupt(); } let showModal = false; @@ -260,7 +271,7 @@ {#if mode === "history" && displayMode === "grid"} {:else} - + {/if} {:else}
diff --git a/src/lib/components/ComfyQueueListDisplay.svelte b/src/lib/components/ComfyQueueListDisplay.svelte index e392825..117afeb 100644 --- a/src/lib/components/ComfyQueueListDisplay.svelte +++ b/src/lib/components/ComfyQueueListDisplay.svelte @@ -7,6 +7,7 @@ export let entries: QueueUIEntry[] = []; export let showPrompt: (entry: QueueUIEntry) => void; export let clearQueue: () => void; + export let deleteEntry: (entry: QueueUIEntry, event: MouseEvent) => void; export let mode: QueueItemType = "queue"; export let imageSize: number = 40; @@ -29,6 +30,11 @@
{#each entries as entry}
showPrompt(entry, e)}> + {#if entry.images.length > 0}
@@ -128,8 +134,9 @@ border-top: 1px solid var(--table-border-color); background: var(--panel-background-fill); max-height: 14rem; + position: relative; - &:hover:not(:has(img:hover)) { + &:hover:not(:has(img:hover)):not(:has(button:hover)) { cursor: pointer; background: var(--block-background-fill); @@ -157,6 +164,34 @@ } } + .list-entry-delete-button { + @include square-button; + + display: flex; + position: absolute; + width: 1.4rem; + height: 1.4rem; + text-align: center; + align-items: center; + font-size: 10pt; + justify-content: center; + text-align: center; + top:0; + right:0.5rem; + margin: 0.5rem; + z-index: 1000000000; + + opacity: 70%; + background: var(--neutral-700); + color: var(--neutral-300); + + &:hover { + opacity: 100%; + color: var(--neutral-100); + } + + } + .list-entry-rest { width: 100%; position: relative; diff --git a/src/lib/stores/queueState.ts b/src/lib/stores/queueState.ts index a3d3bd7..077db00 100644 --- a/src/lib/stores/queueState.ts +++ b/src/lib/stores/queueState.ts @@ -17,6 +17,7 @@ type QueueStateOps = { progressUpdated: (progress: Progress) => void getQueueEntry: (promptID: PromptID) => QueueEntry | null; afterQueued: (workflowID: WorkflowInstID, promptID: PromptID, number: number, prompt: SerializedPromptInputsAll, extraData: any) => void + queueItemDeleted: (type: QueueItemType, id: PromptID) => void; queueCleared: (type: QueueItemType) => void; onExecuted: (promptID: PromptID, nodeID: ComfyNodeID, output: ComfyExecutionResult) => QueueEntry | null } @@ -182,6 +183,39 @@ function findEntryInPending(promptID: PromptID): [number, QueueEntry | null, Wri return [-1, null, null] } +function deleteEntry(promptID: PromptID): boolean { + const state = get(store); + let index = get(state.queuePending).findIndex(e => e.promptID === promptID) + let found = false; + if (index !== -1) { + state.queuePending.update(qp => { + qp.splice(index, 1) + return qp; + }) + found = true; + } + + index = get(state.queueRunning).findIndex(e => e.promptID === promptID) + if (index !== -1) { + state.queueRunning.update(qr => { + qr.splice(index, 1) + return qr; + }) + found = true; + } + + index = get(state.queueCompleted).findIndex(e => e.entry.promptID === promptID) + if (index !== -1) { + state.queueCompleted.update(qc => { + qc.splice(index, 1) + return qc; + }) + found = true; + } + + return found; +} + function moveToRunning(index: number, queue: Writable) { const state = get(store) @@ -295,7 +329,7 @@ function createNewQueueEntry(promptID: PromptID, number: number = -1, prompt: Se return { number, queuedAt: new Date(), // Now - finishedAt: null, + finishedAt: undefined, promptID, prompt, extraData, @@ -364,6 +398,18 @@ function onExecuted(promptID: PromptID, nodeID: ComfyNodeID, outputs: ComfyExecu return entry_; } +function queueItemDeleted(type: QueueItemType, id: PromptID) { + console.debug("[queueState] queueItemDeleted", type, id) + + store.update(s => { + if (!deleteEntry(id)) { + console.error("[queueState] Queue item to delete not found!", type, id); + } + s.isInterrupting = false; + return s; + }) +} + function queueCleared(type: QueueItemType) { console.debug("[queueState] queueCleared", type) @@ -395,6 +441,7 @@ const queueStateStore: WritableQueueStateStore = executionCached, executionError, afterQueued, + queueItemDeleted, queueCleared, getQueueEntry, onExecuted