diff --git a/invokeai/frontend/web/src/app/store/nanostores/bulkDownloadId.ts b/invokeai/frontend/web/src/app/store/nanostores/bulkDownloadId.ts new file mode 100644 index 0000000000..5615124493 --- /dev/null +++ b/invokeai/frontend/web/src/app/store/nanostores/bulkDownloadId.ts @@ -0,0 +1,9 @@ +import { atom } from 'nanostores'; + +export const DEFAULT_BULK_DOWNLOAD_ID = 'default'; + +/** + * The download id for a bulk download. Used for socket subscriptions. + */ + +export const $bulkDownloadId = atom(DEFAULT_BULK_DOWNLOAD_ID); diff --git a/invokeai/frontend/web/src/features/system/store/configSlice.ts b/invokeai/frontend/web/src/features/system/store/configSlice.ts index 1cf62e89c8..94f1f1c64a 100644 --- a/invokeai/frontend/web/src/features/system/store/configSlice.ts +++ b/invokeai/frontend/web/src/features/system/store/configSlice.ts @@ -18,7 +18,7 @@ export const initialConfigState: AppConfig = { shouldUpdateImagesOnConnect: false, shouldFetchMetadataFromApi: false, disabledTabs: [], - disabledFeatures: ['lightbox', 'faceRestore', 'batches', 'bulkDownload'], + disabledFeatures: ['lightbox', 'faceRestore', 'batches'], disabledSDFeatures: ['variation', 'symmetry', 'hires', 'perlinNoise', 'noiseThreshold'], nodesAllowlist: undefined, nodesDenylist: undefined, diff --git a/invokeai/frontend/web/src/services/events/actions.ts b/invokeai/frontend/web/src/services/events/actions.ts index 101e928f79..b80363315e 100644 --- a/invokeai/frontend/web/src/services/events/actions.ts +++ b/invokeai/frontend/web/src/services/events/actions.ts @@ -1,5 +1,8 @@ import { createAction } from '@reduxjs/toolkit'; import type { + BulkDownloadCompletedEvent, + BulkDownloadFailedEvent, + BulkDownloadStartedEvent, GeneratorProgressEvent, GraphExecutionStateCompleteEvent, InvocationCompleteEvent, @@ -64,3 +67,15 @@ export const socketInvocationRetrievalError = createAction<{ export const socketQueueItemStatusChanged = createAction<{ data: QueueItemStatusChangedEvent; }>('socket/socketQueueItemStatusChanged'); + +export const socketBulkDownloadStarted = createAction<{ + data: BulkDownloadStartedEvent; +}>('socket/socketBulkDownloadStarted'); + +export const socketBulkDownloadCompleted = createAction<{ + data: BulkDownloadCompletedEvent; +}>('socket/socketBulkDownloadCompleted'); + +export const socketBulkDownloadFailed = createAction<{ + data: BulkDownloadFailedEvent; +}>('socket/socketBulkDownloadFailed'); diff --git a/invokeai/frontend/web/src/services/events/types.ts b/invokeai/frontend/web/src/services/events/types.ts index 9579b6abc1..092132fea2 100644 --- a/invokeai/frontend/web/src/services/events/types.ts +++ b/invokeai/frontend/web/src/services/events/types.ts @@ -156,7 +156,7 @@ export type InvocationRetrievalErrorEvent = { * * @example socket.on('queue_item_status_changed', (data: QueueItemStatusChangedEvent) => { ... } */ -export type QueueItemStatusChangedEvent = { +export type QueueItemStatusChangedEvent = { queue_id: string; queue_item: { queue_id: string; @@ -191,7 +191,7 @@ export type QueueItemStatusChangedEvent = { failed: number; canceled: number; total: number; - }; + }; }; export type ClientEmitSubscribeQueue = { @@ -202,6 +202,31 @@ export type ClientEmitUnsubscribeQueue = { queue_id: string; }; +export type BulkDownloadStartedEvent = { + bulk_download_id: string; + bulk_download_item_id: string; +}; + +export type BulkDownloadCompletedEvent = { + bulk_download_id: string; + bulk_download_item_id: string; + bulk_download_item_name: string; +}; + +export type BulkDownloadFailedEvent = { + bulk_download_id: string; + bulk_download_item_id: string; + error: string; +} + +export type ClientEmitSubscribeBulkDownload = { + bulk_download_id: string; +}; + +export type ClientEmitUnsubscribeBulkDownload = { + bulk_download_id: string; +}; + export type ServerToClientEvents = { generator_progress: (payload: GeneratorProgressEvent) => void; invocation_complete: (payload: InvocationCompleteEvent) => void; @@ -213,6 +238,9 @@ export type ServerToClientEvents = { session_retrieval_error: (payload: SessionRetrievalErrorEvent) => void; invocation_retrieval_error: (payload: InvocationRetrievalErrorEvent) => void; queue_item_status_changed: (payload: QueueItemStatusChangedEvent) => void; + bulk_download_started: (payload: BulkDownloadStartedEvent) => void; + bulk_download_completed: (payload: BulkDownloadCompletedEvent) => void; + bulk_download_failed: (payload: BulkDownloadFailedEvent) => void; }; export type ClientToServerEvents = { @@ -220,4 +248,6 @@ export type ClientToServerEvents = { disconnect: () => void; subscribe_queue: (payload: ClientEmitSubscribeQueue) => void; unsubscribe_queue: (payload: ClientEmitUnsubscribeQueue) => void; + subscribe_bulk_download: (payload: ClientEmitSubscribeBulkDownload) => void; + unsubscribe_bulk_download: (payload: ClientEmitUnsubscribeBulkDownload) => void; }; diff --git a/invokeai/frontend/web/src/services/events/util/setEventListeners.ts b/invokeai/frontend/web/src/services/events/util/setEventListeners.ts index c66defee60..d851a185ff 100644 --- a/invokeai/frontend/web/src/services/events/util/setEventListeners.ts +++ b/invokeai/frontend/web/src/services/events/util/setEventListeners.ts @@ -1,8 +1,12 @@ +import { $bulkDownloadId } from 'app/store/nanostores/bulkDownloadId'; import { $queueId } from 'app/store/nanostores/queueId'; import type { AppDispatch } from 'app/store/store'; import { addToast } from 'features/system/store/systemSlice'; import { makeToast } from 'features/system/util/makeToast'; import { + socketBulkDownloadCompleted, + socketBulkDownloadFailed, + socketBulkDownloadStarted, socketConnected, socketDisconnected, socketGeneratorProgress, @@ -34,6 +38,8 @@ export const setEventListeners = (arg: SetEventListenersArg) => { dispatch(socketConnected()); const queue_id = $queueId.get(); socket.emit('subscribe_queue', { queue_id }); + const bulk_download_id = $bulkDownloadId.get(); + socket.emit('subscribe_bulk_download', { bulk_download_id }); }); socket.on('connect_error', (error) => { @@ -150,4 +156,16 @@ export const setEventListeners = (arg: SetEventListenersArg) => { socket.on('queue_item_status_changed', (data) => { dispatch(socketQueueItemStatusChanged({ data })); }); + + socket.on('bulk_download_started', (data) => { + dispatch(socketBulkDownloadStarted({ data })); + }); + + socket.on('bulk_download_completed', (data) => { + dispatch(socketBulkDownloadCompleted({ data })); + }); + + socket.on('bulk_download_failed', (data) => { + dispatch(socketBulkDownloadFailed({ data })); + }); };