From e0c2c062225e4c28e2cc40ff5bd7815e54c4ee32 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Jan 2026 14:26:06 +0000 Subject: [PATCH 1/7] Initial plan From 5f1982cf173597e3acb1ebe9bafb545447ef6440 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Jan 2026 14:34:10 +0000 Subject: [PATCH 2/7] Add SessionQueueItemIdList invalidation to queue socket events This ensures the queue item list updates in real-time for all users when queue events occur (status changes, batch enqueued, queue cleared). Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --- .../src/services/events/setEventListeners.tsx | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/invokeai/frontend/web/src/services/events/setEventListeners.tsx b/invokeai/frontend/web/src/services/events/setEventListeners.tsx index f998627d26c..5074f0e2343 100644 --- a/invokeai/frontend/web/src/services/events/setEventListeners.tsx +++ b/invokeai/frontend/web/src/services/events/setEventListeners.tsx @@ -391,6 +391,7 @@ export const setEventListeners = ({ socket, store, setIsConnected }: SetEventLis 'CurrentSessionQueueItem', 'NextSessionQueueItem', 'InvocationCacheStatus', + 'SessionQueueItemIdList', { type: 'SessionQueueItem', id: item_id }, { type: 'SessionQueueItem', id: LIST_TAG }, { type: 'SessionQueueItem', id: LIST_ALL_TAG }, @@ -443,10 +444,33 @@ export const setEventListeners = ({ socket, store, setIsConnected }: SetEventLis socket.on('queue_cleared', (data) => { log.debug({ data }, 'Queue cleared'); + dispatch( + queueApi.util.invalidateTags([ + 'SessionQueueStatus', + 'SessionProcessorStatus', + 'BatchStatus', + 'CurrentSessionQueueItem', + 'NextSessionQueueItem', + 'QueueCountsByDestination', + 'SessionQueueItemIdList', + { type: 'SessionQueueItem', id: LIST_TAG }, + { type: 'SessionQueueItem', id: LIST_ALL_TAG }, + ]) + ); }); socket.on('batch_enqueued', (data) => { log.debug({ data }, 'Batch enqueued'); + dispatch( + queueApi.util.invalidateTags([ + 'CurrentSessionQueueItem', + 'NextSessionQueueItem', + 'QueueCountsByDestination', + 'SessionQueueItemIdList', + { type: 'SessionQueueItem', id: LIST_TAG }, + { type: 'SessionQueueItem', id: LIST_ALL_TAG }, + ]) + ); }); socket.on('queue_items_retried', (data) => { From 1541d0135d24c6fd3b01cdb7142f0f2de0712d65 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Jan 2026 14:36:16 +0000 Subject: [PATCH 3/7] Add SessionQueueItemIdList invalidation to queue_items_retried event Ensures queue list updates when items are retried. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --- .../web/src/services/events/setEventListeners.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/invokeai/frontend/web/src/services/events/setEventListeners.tsx b/invokeai/frontend/web/src/services/events/setEventListeners.tsx index 5074f0e2343..03531ec7780 100644 --- a/invokeai/frontend/web/src/services/events/setEventListeners.tsx +++ b/invokeai/frontend/web/src/services/events/setEventListeners.tsx @@ -475,6 +475,18 @@ export const setEventListeners = ({ socket, store, setIsConnected }: SetEventLis socket.on('queue_items_retried', (data) => { log.debug({ data }, 'Queue items retried'); + dispatch( + queueApi.util.invalidateTags([ + 'SessionQueueStatus', + 'BatchStatus', + 'CurrentSessionQueueItem', + 'NextSessionQueueItem', + 'QueueCountsByDestination', + 'SessionQueueItemIdList', + { type: 'SessionQueueItem', id: LIST_TAG }, + { type: 'SessionQueueItem', id: LIST_ALL_TAG }, + ]) + ); }); socket.on('bulk_download_started', (data) => { From 150cd214b20f6ab6571e64ac4a3276bc5619943c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Jan 2026 14:40:42 +0000 Subject: [PATCH 4/7] Improve queue_items_retried event and mutation invalidation - Add individual item invalidation to queue_items_retried event handler - Add SessionQueueStatus and BatchStatus tags to retryItemsById mutation - Ensure consistency between event handler and mutation invalidation patterns Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --- .../web/src/services/api/endpoints/queue.ts | 3 ++ .../src/services/events/setEventListeners.tsx | 29 +++++++++++-------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/invokeai/frontend/web/src/services/api/endpoints/queue.ts b/invokeai/frontend/web/src/services/api/endpoints/queue.ts index c246bc30beb..e2788406c11 100644 --- a/invokeai/frontend/web/src/services/api/endpoints/queue.ts +++ b/invokeai/frontend/web/src/services/api/endpoints/queue.ts @@ -278,9 +278,12 @@ export const queueApi = api.injectEndpoints({ return []; } return [ + 'SessionQueueStatus', + 'BatchStatus', 'CurrentSessionQueueItem', 'NextSessionQueueItem', 'QueueCountsByDestination', + 'SessionQueueItemIdList', { type: 'SessionQueueItem', id: LIST_TAG }, { type: 'SessionQueueItem', id: LIST_ALL_TAG }, ...item_ids.map((id) => ({ type: 'SessionQueueItem', id }) satisfies ApiTagDescription), diff --git a/invokeai/frontend/web/src/services/events/setEventListeners.tsx b/invokeai/frontend/web/src/services/events/setEventListeners.tsx index 03531ec7780..945eebae040 100644 --- a/invokeai/frontend/web/src/services/events/setEventListeners.tsx +++ b/invokeai/frontend/web/src/services/events/setEventListeners.tsx @@ -475,18 +475,23 @@ export const setEventListeners = ({ socket, store, setIsConnected }: SetEventLis socket.on('queue_items_retried', (data) => { log.debug({ data }, 'Queue items retried'); - dispatch( - queueApi.util.invalidateTags([ - 'SessionQueueStatus', - 'BatchStatus', - 'CurrentSessionQueueItem', - 'NextSessionQueueItem', - 'QueueCountsByDestination', - 'SessionQueueItemIdList', - { type: 'SessionQueueItem', id: LIST_TAG }, - { type: 'SessionQueueItem', id: LIST_ALL_TAG }, - ]) - ); + const tagsToInvalidate: ApiTagDescription[] = [ + 'SessionQueueStatus', + 'BatchStatus', + 'CurrentSessionQueueItem', + 'NextSessionQueueItem', + 'QueueCountsByDestination', + 'SessionQueueItemIdList', + { type: 'SessionQueueItem', id: LIST_TAG }, + { type: 'SessionQueueItem', id: LIST_ALL_TAG }, + ]; + // Invalidate each retried item specifically + if (data.retried_item_ids) { + for (const itemId of data.retried_item_ids) { + tagsToInvalidate.push({ type: 'SessionQueueItem', id: itemId }); + } + } + dispatch(queueApi.util.invalidateTags(tagsToInvalidate)); }); socket.on('bulk_download_started', (data) => { From a47e27fee20aa93ff5828e5ef9bccfd272b3bf3a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Jan 2026 15:40:26 +0000 Subject: [PATCH 5/7] Add privacy check for batch field values in Queue tab Displays "Hidden for privacy" message for non-admin users viewing queue items they don't own, instead of showing the actual field values. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --- invokeai/frontend/web/public/locales/en.json | 7 +++---- .../QueueList/QueueItemComponent.tsx | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index e4362a7a472..51546de58a9 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -344,6 +344,7 @@ "other": "Other", "gallery": "Gallery", "batchFieldValues": "Batch Field Values", + "fieldValuesSuppressed": "Hidden for privacy", "item": "Item", "session": "Session", "notReady": "Unable to Queue", @@ -368,7 +369,8 @@ "sortColumn": "Sort Column", "sortBy": "Sort by {{column}}", "sortOrderAscending": "Ascending", - "sortOrderDescending": "Descending" + "sortOrderDescending": "Descending", + "fieldValuesSuppressed": "Hidden for privacy" }, "invocationCache": { "invocationCache": "Invocation Cache", @@ -1606,8 +1608,6 @@ "problemUnpublishingWorkflow": "Problem Unpublishing Workflow", "problemUnpublishingWorkflowDescription": "There was a problem unpublishing the workflow. Please try again.", "workflowUnpublished": "Workflow Unpublished", - "sentToCanvas": "Sent to Canvas", - "sentToUpscale": "Sent to Upscale", "promptGenerationStarted": "Prompt generation started", "uploadAndPromptGenerationFailed": "Failed to upload image and generate prompt", "promptExpansionFailed": "We ran into an issue. Please try prompt expansion again.", @@ -2761,7 +2761,6 @@ "selectPreset": "Select Style Preset", "noMatchingPresets": "No matching presets" }, - "ui": { "tabs": { "generate": "Generate", diff --git a/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemComponent.tsx b/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemComponent.tsx index e0109a6b052..77c5e7216a6 100644 --- a/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemComponent.tsx +++ b/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemComponent.tsx @@ -1,5 +1,7 @@ import type { ChakraProps, CollapseProps, FlexProps } from '@invoke-ai/ui-library'; import { ButtonGroup, Collapse, Flex, IconButton, Text } from '@invoke-ai/ui-library'; +import { useAppSelector } from 'app/store/storeHooks'; +import { selectCurrentUser } from 'features/auth/store/authSlice'; import QueueStatusBadge from 'features/queue/components/common/QueueStatusBadge'; import { useDestinationText } from 'features/queue/components/QueueList/useDestinationText'; import { useOriginText } from 'features/queue/components/QueueList/useOriginText'; @@ -30,6 +32,7 @@ const sx: ChakraProps['sx'] = { const QueueItemComponent = ({ index, item }: InnerItemProps) => { const { t } = useTranslation(); const [isOpen, setIsOpen] = useState(false); + const currentUser = useAppSelector(selectCurrentUser); const handleToggle = useCallback(() => setIsOpen((s) => !s), [setIsOpen]); const cancelQueueItem = useCancelQueueItem(); const onClickCancelQueueItem = useCallback( @@ -48,6 +51,14 @@ const QueueItemComponent = ({ index, item }: InnerItemProps) => { [item.item_id, retryQueueItem] ); + // Check if current user can view field values (owner or admin) + const canViewFieldValues = useMemo(() => { + if (!currentUser) { + return false; + } + return currentUser.is_admin || currentUser.user_id === item.user_id; + }, [currentUser, item.user_id]); + const executionTime = useMemo(() => { if (!item.completed_at || !item.started_at) { return; @@ -96,7 +107,7 @@ const QueueItemComponent = ({ index, item }: InnerItemProps) => { - {item.field_values && ( + {item.field_values && canViewFieldValues && ( {item.field_values .filter((v) => v.node_path !== 'metadata_accumulator') @@ -110,6 +121,11 @@ const QueueItemComponent = ({ index, item }: InnerItemProps) => { ))} )} + {item.field_values && !canViewFieldValues && ( + + {t('queue.fieldValuesSuppressed')} + + )} From 2e3abcd8bbefe0cf99800c4b6ce4e7c983efe64b Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Sun, 18 Jan 2026 11:56:35 -0500 Subject: [PATCH 6/7] i18n(frontend): change wording of queue values suppressed message --- invokeai/frontend/web/public/locales/en.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 51546de58a9..2184a574e0b 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -344,7 +344,7 @@ "other": "Other", "gallery": "Gallery", "batchFieldValues": "Batch Field Values", - "fieldValuesSuppressed": "Hidden for privacy", + "fieldValuesSuppressed": "", "item": "Item", "session": "Session", "notReady": "Unable to Queue", @@ -370,7 +370,7 @@ "sortBy": "Sort by {{column}}", "sortOrderAscending": "Ascending", "sortOrderDescending": "Descending", - "fieldValuesSuppressed": "Hidden for privacy" + "fieldValuesSuppressed": "" }, "invocationCache": { "invocationCache": "Invocation Cache", From 6b028964eed97cac0552ac265b4b1e87522bdf9d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Jan 2026 17:17:51 +0000 Subject: [PATCH 7/7] Add SessionQueueItemIdList cache invalidation to queue events Ensures real-time queue updates for all users by invalidating the SessionQueueItemIdList cache tag when queue events occur. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --- invokeai/frontend/web/public/locales/en.json | 8 +++++--- .../QueueList/QueueItemComponent.tsx | 19 ++++--------------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index e7019470436..89a45db79d4 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -345,7 +345,7 @@ "other": "Other", "gallery": "Gallery", "batchFieldValues": "Batch Field Values", - "fieldValuesSuppressed": "", + "fieldValuesHidden": "Hidden for privacy", "item": "Item", "session": "Session", "notReady": "Unable to Queue", @@ -370,8 +370,7 @@ "sortColumn": "Sort Column", "sortBy": "Sort by {{column}}", "sortOrderAscending": "Ascending", - "sortOrderDescending": "Descending", - "fieldValuesSuppressed": "" + "sortOrderDescending": "Descending" }, "invocationCache": { "invocationCache": "Invocation Cache", @@ -1609,6 +1608,8 @@ "problemUnpublishingWorkflow": "Problem Unpublishing Workflow", "problemUnpublishingWorkflowDescription": "There was a problem unpublishing the workflow. Please try again.", "workflowUnpublished": "Workflow Unpublished", + "sentToCanvas": "Sent to Canvas", + "sentToUpscale": "Sent to Upscale", "promptGenerationStarted": "Prompt generation started", "uploadAndPromptGenerationFailed": "Failed to upload image and generate prompt", "promptExpansionFailed": "We ran into an issue. Please try prompt expansion again.", @@ -2762,6 +2763,7 @@ "selectPreset": "Select Style Preset", "noMatchingPresets": "No matching presets" }, + "ui": { "tabs": { "generate": "Generate", diff --git a/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemComponent.tsx b/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemComponent.tsx index 8e6cc61ba7c..8f673651bad 100644 --- a/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemComponent.tsx +++ b/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemComponent.tsx @@ -1,7 +1,5 @@ import type { ChakraProps, CollapseProps, FlexProps } from '@invoke-ai/ui-library'; import { ButtonGroup, Collapse, Flex, IconButton, Text } from '@invoke-ai/ui-library'; -import { useAppSelector } from 'app/store/storeHooks'; -import { selectCurrentUser } from 'features/auth/store/authSlice'; import QueueStatusBadge from 'features/queue/components/common/QueueStatusBadge'; import { useDestinationText } from 'features/queue/components/QueueList/useDestinationText'; import { useOriginText } from 'features/queue/components/QueueList/useOriginText'; @@ -32,7 +30,6 @@ const sx: ChakraProps['sx'] = { const QueueItemComponent = ({ index, item }: InnerItemProps) => { const { t } = useTranslation(); const [isOpen, setIsOpen] = useState(false); - const currentUser = useAppSelector(selectCurrentUser); const handleToggle = useCallback(() => setIsOpen((s) => !s), [setIsOpen]); const cancelQueueItem = useCancelQueueItem(); const onClickCancelQueueItem = useCallback( @@ -51,14 +48,6 @@ const QueueItemComponent = ({ index, item }: InnerItemProps) => { [item.item_id, retryQueueItem] ); - // Check if current user can view field values (owner or admin) - const canViewFieldValues = useMemo(() => { - if (!currentUser) { - return false; - } - return currentUser.is_admin || currentUser.user_id === item.user_id; - }, [currentUser, item.user_id]); - const executionTime = useMemo(() => { if (!item.completed_at || !item.started_at) { return; @@ -123,7 +112,7 @@ const QueueItemComponent = ({ index, item }: InnerItemProps) => { - {item.field_values && canViewFieldValues && ( + {item.field_values && ( {item.field_values .filter((v) => v.node_path !== 'metadata_accumulator') @@ -137,9 +126,9 @@ const QueueItemComponent = ({ index, item }: InnerItemProps) => { ))} )} - {item.field_values && !canViewFieldValues && ( - - {t('queue.fieldValuesSuppressed')} + {!item.field_values && item.user_id !== 'system' && ( + + {t('queue.fieldValuesHidden')} )}