Delete queue/history item
This commit is contained in:
@@ -331,7 +331,7 @@ export default class ComfyAPI {
|
|||||||
* @param {string} type The type of item to delete, queue or history
|
* @param {string} type The type of item to delete, queue or history
|
||||||
* @param {number} id The id of the item to delete
|
* @param {number} id The id of the item to delete
|
||||||
*/
|
*/
|
||||||
async deleteItem(type: QueueItemType, id: number): Promise<Response> {
|
async deleteItem(type: QueueItemType, id: PromptID): Promise<Response> {
|
||||||
return this.postItem(type, { delete: [id] });
|
return this.postItem(type, { delete: [id] });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -509,7 +509,35 @@ export default class ComfyApp {
|
|||||||
this.api.init();
|
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) {
|
async clearQueue(type: QueueItemType) {
|
||||||
|
if (get(queueState).isInterrupting)
|
||||||
|
return
|
||||||
|
|
||||||
queueState.update(s => { s.isInterrupting = true; return s; })
|
queueState.update(s => { s.isInterrupting = true; return s; })
|
||||||
await this.api.clearItems(type)
|
await this.api.clearItems(type)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|||||||
@@ -85,6 +85,27 @@
|
|||||||
changed = false;
|
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() {
|
async function clearQueue() {
|
||||||
await app.clearQueue(mode);
|
await app.clearQueue(mode);
|
||||||
|
|
||||||
@@ -188,17 +209,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function interrupt() {
|
async function interrupt() {
|
||||||
if ($queueState.isInterrupting)
|
await app.interrupt();
|
||||||
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 })
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let showModal = false;
|
let showModal = false;
|
||||||
@@ -260,7 +271,7 @@
|
|||||||
{#if mode === "history" && displayMode === "grid"}
|
{#if mode === "history" && displayMode === "grid"}
|
||||||
<ComfyQueueGridDisplay entries={_entries} {showPrompt} {clearQueue} {mode} bind:gridColumns />
|
<ComfyQueueGridDisplay entries={_entries} {showPrompt} {clearQueue} {mode} bind:gridColumns />
|
||||||
{:else}
|
{:else}
|
||||||
<ComfyQueueListDisplay entries={_entries} {showPrompt} {clearQueue} {mode} bind:imageSize />
|
<ComfyQueueListDisplay entries={_entries} {showPrompt} {clearQueue} {mode} {deleteEntry} bind:imageSize />
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<div class="queue-empty">
|
<div class="queue-empty">
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
export let entries: QueueUIEntry[] = [];
|
export let entries: QueueUIEntry[] = [];
|
||||||
export let showPrompt: (entry: QueueUIEntry) => void;
|
export let showPrompt: (entry: QueueUIEntry) => void;
|
||||||
export let clearQueue: () => void;
|
export let clearQueue: () => void;
|
||||||
|
export let deleteEntry: (entry: QueueUIEntry, event: MouseEvent) => void;
|
||||||
export let mode: QueueItemType = "queue";
|
export let mode: QueueItemType = "queue";
|
||||||
export let imageSize: number = 40;
|
export let imageSize: number = 40;
|
||||||
</script>
|
</script>
|
||||||
@@ -29,6 +30,11 @@
|
|||||||
<div class="list-entries {mode}-mode" style:--imageSize={imageSize}>
|
<div class="list-entries {mode}-mode" style:--imageSize={imageSize}>
|
||||||
{#each entries as entry}
|
{#each entries as entry}
|
||||||
<div class="list-entry {entry.status}" on:click={(e) => showPrompt(entry, e)}>
|
<div class="list-entry {entry.status}" on:click={(e) => showPrompt(entry, e)}>
|
||||||
|
<button class="list-entry-delete-button secondary"
|
||||||
|
on:click={(e) => deleteEntry(entry, e)}
|
||||||
|
disabled={$queueState.isInterrupting}>
|
||||||
|
<span>✕</span>
|
||||||
|
</button>
|
||||||
{#if entry.images.length > 0}
|
{#if entry.images.length > 0}
|
||||||
<div class="list-entry-images"
|
<div class="list-entry-images"
|
||||||
style="--cols: {Math.ceil(Math.sqrt(Math.min(entry.images.length, 4)))}" >
|
style="--cols: {Math.ceil(Math.sqrt(Math.min(entry.images.length, 4)))}" >
|
||||||
@@ -128,8 +134,9 @@
|
|||||||
border-top: 1px solid var(--table-border-color);
|
border-top: 1px solid var(--table-border-color);
|
||||||
background: var(--panel-background-fill);
|
background: var(--panel-background-fill);
|
||||||
max-height: 14rem;
|
max-height: 14rem;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
&:hover:not(:has(img:hover)) {
|
&:hover:not(:has(img:hover)):not(:has(button:hover)) {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background: var(--block-background-fill);
|
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 {
|
.list-entry-rest {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ type QueueStateOps = {
|
|||||||
progressUpdated: (progress: Progress) => void
|
progressUpdated: (progress: Progress) => void
|
||||||
getQueueEntry: (promptID: PromptID) => QueueEntry | null;
|
getQueueEntry: (promptID: PromptID) => QueueEntry | null;
|
||||||
afterQueued: (workflowID: WorkflowInstID, promptID: PromptID, number: number, prompt: SerializedPromptInputsAll, extraData: any) => void
|
afterQueued: (workflowID: WorkflowInstID, promptID: PromptID, number: number, prompt: SerializedPromptInputsAll, extraData: any) => void
|
||||||
|
queueItemDeleted: (type: QueueItemType, id: PromptID) => void;
|
||||||
queueCleared: (type: QueueItemType) => void;
|
queueCleared: (type: QueueItemType) => void;
|
||||||
onExecuted: (promptID: PromptID, nodeID: ComfyNodeID, output: ComfyExecutionResult) => QueueEntry | null
|
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]
|
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<QueueEntry[]>) {
|
function moveToRunning(index: number, queue: Writable<QueueEntry[]>) {
|
||||||
const state = get(store)
|
const state = get(store)
|
||||||
|
|
||||||
@@ -295,7 +329,7 @@ function createNewQueueEntry(promptID: PromptID, number: number = -1, prompt: Se
|
|||||||
return {
|
return {
|
||||||
number,
|
number,
|
||||||
queuedAt: new Date(), // Now
|
queuedAt: new Date(), // Now
|
||||||
finishedAt: null,
|
finishedAt: undefined,
|
||||||
promptID,
|
promptID,
|
||||||
prompt,
|
prompt,
|
||||||
extraData,
|
extraData,
|
||||||
@@ -364,6 +398,18 @@ function onExecuted(promptID: PromptID, nodeID: ComfyNodeID, outputs: ComfyExecu
|
|||||||
return entry_;
|
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) {
|
function queueCleared(type: QueueItemType) {
|
||||||
console.debug("[queueState] queueCleared", type)
|
console.debug("[queueState] queueCleared", type)
|
||||||
|
|
||||||
@@ -395,6 +441,7 @@ const queueStateStore: WritableQueueStateStore =
|
|||||||
executionCached,
|
executionCached,
|
||||||
executionError,
|
executionError,
|
||||||
afterQueued,
|
afterQueued,
|
||||||
|
queueItemDeleted,
|
||||||
queueCleared,
|
queueCleared,
|
||||||
getQueueEntry,
|
getQueueEntry,
|
||||||
onExecuted
|
onExecuted
|
||||||
|
|||||||
Reference in New Issue
Block a user