Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions src/components/queue/QueueProgressOverlay.vue
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ import { useQueueProgress } from '@/composables/queue/useQueueProgress'
import { useResultGallery } from '@/composables/queue/useResultGallery'
import { useErrorHandling } from '@/composables/useErrorHandling'
import { useAssetSelectionStore } from '@/platform/assets/composables/useAssetSelectionStore'
import { isCloud } from '@/platform/distribution/types'
import { api } from '@/scripts/api'
import { useAssetsStore } from '@/stores/assetsStore'
import { useCommandStore } from '@/stores/commandStore'
Expand Down Expand Up @@ -263,11 +264,21 @@ const cancelQueuedWorkflows = wrapWithErrorHandlingAsync(async () => {

const interruptAll = wrapWithErrorHandlingAsync(async () => {
const tasks = queueStore.runningTasks
await Promise.all(
tasks
.filter((task) => task.promptId != null)
.map((task) => api.interrupt(task.promptId))
)
const promptIds = tasks
.map((task) => task.promptId)
.filter((id): id is string => typeof id === 'string' && id.length > 0)

if (!promptIds.length) return

// Cloud backend supports cancelling specific jobs via /queue delete,
// while /interrupt always targets the "first" job. Use the targeted API
// on cloud to ensure we cancel the workflow the user clicked.
if (isCloud) {
await Promise.all(promptIds.map((id) => api.deleteItem('queue', id)))
return
}

await Promise.all(promptIds.map((id) => api.interrupt(id)))
})
Comment on lines 265 to 282
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

interruptAll now safely filters promptIds; consider deduping IDs as a minor improvement

The updated logic correctly:

  • Extracts promptId from runningTasks
  • Uses a type guard to keep only non-empty strings
  • Exits early when there are no valid IDs
  • Routes to /queue DELETE on cloud and /interrupt otherwise, all wrapped in existing async error handling

As a minor optimization (especially if runningTasks can contain multiple entries with the same promptId), you could deduplicate before issuing API calls:

 const interruptAll = wrapWithErrorHandlingAsync(async () => {
   const tasks = queueStore.runningTasks
   const promptIds = tasks
     .map((task) => task.promptId)
     .filter((id): id is string => typeof id === 'string' && id.length > 0)

   if (!promptIds.length) return

+  const uniquePromptIds = [...new Set(promptIds)]
+
   // Cloud backend supports cancelling specific jobs via /queue delete,
   // while /interrupt always targets the "first" job. Use the targeted API
   // on cloud to ensure we cancel the workflow the user clicked.
   if (isCloud) {
-    await Promise.all(promptIds.map((id) => api.deleteItem('queue', id)))
+    await Promise.all(uniquePromptIds.map((id) => api.deleteItem('queue', id)))
     return
   }

-  await Promise.all(promptIds.map((id) => api.interrupt(id)))
+  await Promise.all(uniquePromptIds.map((id) => api.interrupt(id)))
 })

This keeps behavior the same in the common case while avoiding redundant calls if duplicates ever appear.

🤖 Prompt for AI Agents
In src/components/queue/QueueProgressOverlay.vue around lines 265 to 282, the
interruptAll handler filters out invalid promptIds but may call the API multiple
times for duplicate IDs; deduplicate promptIds after filtering (e.g., using a
Set or Array.from(new Set(...))) and then use that deduplicated list for the
Promise.all calls so each unique promptId is cancelled exactly once for both the
cloud delete path and the local interrupt path.


const showClearHistoryDialog = () => {
Expand Down