diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json
index af8795dd5e..5179f30002 100644
--- a/invokeai/frontend/web/public/locales/en.json
+++ b/invokeai/frontend/web/public/locales/en.json
@@ -1962,6 +1962,7 @@
"recalculateRects": "Recalculate Rects",
"clipToBbox": "Clip Strokes to Bbox",
"outputOnlyMaskedRegions": "Output Only Generated Regions",
+ "saveAllStagingImagesToGallery": "Save All Staging Images to Gallery",
"addLayer": "Add Layer",
"duplicate": "Duplicate",
"moveToFront": "Move to Front",
@@ -2330,6 +2331,9 @@
"label": "Preserve Masked Region",
"alert": "Preserving Masked Region"
},
+ "saveAllStagingImagesToGallery": {
+ "alert": "Saving All Staging Images to Gallery"
+ },
"isolatedStagingPreview": "Isolated Staging Preview",
"isolatedPreview": "Isolated Preview",
"isolatedLayerPreview": "Isolated Layer Preview",
diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasAlerts/CanvasAlertsSaveAllStagingImagesToGallery.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasAlerts/CanvasAlertsSaveAllStagingImagesToGallery.tsx
new file mode 100644
index 0000000000..63faec7719
--- /dev/null
+++ b/invokeai/frontend/web/src/features/controlLayers/components/CanvasAlerts/CanvasAlertsSaveAllStagingImagesToGallery.tsx
@@ -0,0 +1,23 @@
+import { Alert, AlertIcon, AlertTitle } from '@invoke-ai/ui-library';
+import { useAppSelector } from 'app/store/storeHooks';
+import { selectSaveAllStagingImagesToGallery } from 'features/controlLayers/store/canvasSettingsSlice';
+import { memo } from 'react';
+import { useTranslation } from 'react-i18next';
+
+export const CanvasAlertsSaveAllStagingImagesToGallery = memo(() => {
+ const { t } = useTranslation();
+ const saveAllStagingImagesToGallery = useAppSelector(selectSaveAllStagingImagesToGallery);
+
+ if (!saveAllStagingImagesToGallery) {
+ return null;
+ }
+
+ return (
+
+
+ {t('controlLayers.settings.saveAllStagingImagesToGallery.alert')}
+
+ );
+});
+
+CanvasAlertsSaveAllStagingImagesToGallery.displayName = 'CanvasAlertsSaveAllStagingImagesToGallery';
diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Settings/CanvasSettingsPopover.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Settings/CanvasSettingsPopover.tsx
index df42fb9ded..e5cd083eba 100644
--- a/invokeai/frontend/web/src/features/controlLayers/components/Settings/CanvasSettingsPopover.tsx
+++ b/invokeai/frontend/web/src/features/controlLayers/components/Settings/CanvasSettingsPopover.tsx
@@ -26,6 +26,7 @@ import { CanvasSettingsPreserveMaskCheckbox } from 'features/controlLayers/compo
import { CanvasSettingsPressureSensitivityCheckbox } from 'features/controlLayers/components/Settings/CanvasSettingsPressureSensitivity';
import { CanvasSettingsRecalculateRectsButton } from 'features/controlLayers/components/Settings/CanvasSettingsRecalculateRectsButton';
import { CanvasSettingsRuleOfThirdsSwitch } from 'features/controlLayers/components/Settings/CanvasSettingsRuleOfThirdsGuideSwitch';
+import { CanvasSettingsSaveAllStagingImagesToGalleryCheckbox } from 'features/controlLayers/components/Settings/CanvasSettingsSaveAllStagingImagesToGalleryCheckbox';
import { CanvasSettingsShowHUDSwitch } from 'features/controlLayers/components/Settings/CanvasSettingsShowHUDSwitch';
import { CanvasSettingsShowProgressOnCanvas } from 'features/controlLayers/components/Settings/CanvasSettingsShowProgressOnCanvasSwitch';
import { memo } from 'react';
@@ -61,6 +62,7 @@ export const CanvasSettingsPopover = memo(() => {
+
diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Settings/CanvasSettingsSaveAllStagingImagesToGalleryCheckbox.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Settings/CanvasSettingsSaveAllStagingImagesToGalleryCheckbox.tsx
new file mode 100644
index 0000000000..633056dfbb
--- /dev/null
+++ b/invokeai/frontend/web/src/features/controlLayers/components/Settings/CanvasSettingsSaveAllStagingImagesToGalleryCheckbox.tsx
@@ -0,0 +1,25 @@
+import { Checkbox, FormControl, FormLabel } from '@invoke-ai/ui-library';
+import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import {
+ selectSaveAllStagingImagesToGallery,
+ settingsSaveAllStagingImagesToGalleryToggled,
+} from 'features/controlLayers/store/canvasSettingsSlice';
+import { memo, useCallback } from 'react';
+import { useTranslation } from 'react-i18next';
+
+export const CanvasSettingsSaveAllStagingImagesToGalleryCheckbox = memo(() => {
+ const { t } = useTranslation();
+ const dispatch = useAppDispatch();
+ const saveAllStagingImagesToGallery = useAppSelector(selectSaveAllStagingImagesToGallery);
+ const onChange = useCallback(() => {
+ dispatch(settingsSaveAllStagingImagesToGalleryToggled());
+ }, [dispatch]);
+ return (
+
+ {t('controlLayers.saveAllStagingImagesToGallery')}
+
+
+ );
+});
+
+CanvasSettingsSaveAllStagingImagesToGalleryCheckbox.displayName = 'CanvasSettingsSaveAllStagingImagesToGalleryCheckbox';
diff --git a/invokeai/frontend/web/src/features/controlLayers/store/canvasSettingsSlice.ts b/invokeai/frontend/web/src/features/controlLayers/store/canvasSettingsSlice.ts
index 785c9f9099..ac24b0af82 100644
--- a/invokeai/frontend/web/src/features/controlLayers/store/canvasSettingsSlice.ts
+++ b/invokeai/frontend/web/src/features/controlLayers/store/canvasSettingsSlice.ts
@@ -77,6 +77,10 @@ type CanvasSettingsState = {
* Whether to show the rule of thirds composition guide overlay on the canvas.
*/
ruleOfThirds: boolean;
+ /**
+ * Whether to save all staging images to the gallery instead of keeping them as intermediate images.
+ */
+ saveAllStagingImagesToGallery: boolean;
};
const initialState: CanvasSettingsState = {
@@ -97,6 +101,7 @@ const initialState: CanvasSettingsState = {
isolatedLayerPreview: true,
pressureSensitivity: true,
ruleOfThirds: false,
+ saveAllStagingImagesToGallery: false,
};
export const canvasSettingsSlice = createSlice({
@@ -154,6 +159,9 @@ export const canvasSettingsSlice = createSlice({
settingsRuleOfThirdsToggled: (state) => {
state.ruleOfThirds = !state.ruleOfThirds;
},
+ settingsSaveAllStagingImagesToGalleryToggled: (state) => {
+ state.saveAllStagingImagesToGallery = !state.saveAllStagingImagesToGallery;
+ },
},
});
@@ -175,6 +183,7 @@ export const {
settingsIsolatedLayerPreviewToggled,
settingsPressureSensitivityToggled,
settingsRuleOfThirdsToggled,
+ settingsSaveAllStagingImagesToGalleryToggled,
} = canvasSettingsSlice.actions;
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
@@ -209,3 +218,6 @@ export const selectIsolatedStagingPreview = createCanvasSettingsSelector((settin
export const selectIsolatedLayerPreview = createCanvasSettingsSelector((settings) => settings.isolatedLayerPreview);
export const selectPressureSensitivity = createCanvasSettingsSelector((settings) => settings.pressureSensitivity);
export const selectRuleOfThirds = createCanvasSettingsSelector((settings) => settings.ruleOfThirds);
+export const selectSaveAllStagingImagesToGallery = createCanvasSettingsSelector(
+ (settings) => settings.saveAllStagingImagesToGallery
+);
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ModelInstallQueue/ModelInstallQueue.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ModelInstallQueue/ModelInstallQueue.tsx
index f124462e8b..c2443dde6b 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ModelInstallQueue/ModelInstallQueue.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ModelInstallQueue/ModelInstallQueue.tsx
@@ -55,9 +55,7 @@ export const ModelInstallQueue = memo(() => {
- {data?.map((model) => (
-
- ))}
+ {data?.map((model) => )}
diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts b/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts
index 6549f07d07..c273d16e19 100644
--- a/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts
+++ b/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts
@@ -1,6 +1,7 @@
import { createSelector } from '@reduxjs/toolkit';
import type { RootState } from 'app/store/store';
import { getPrefixedId } from 'features/controlLayers/konva/util';
+import { selectSaveAllStagingImagesToGallery } from 'features/controlLayers/store/canvasSettingsSlice';
import {
selectImg2imgStrength,
selectMainModelConfig,
@@ -44,8 +45,11 @@ export const selectCanvasOutputFields = (state: RootState) => {
// Advanced session means working on canvas - images are not saved to gallery or added to a board.
// Simple session means working in YOLO mode - images are saved to gallery & board.
const tab = selectActiveTab(state);
- const is_intermediate = tab === 'canvas';
- const board = tab === 'canvas' ? undefined : getBoardField(state);
+ const saveAllStagingImagesToGallery = selectSaveAllStagingImagesToGallery(state);
+
+ // If we're on canvas and the save all staging images setting is enabled, save to gallery
+ const is_intermediate = tab === 'canvas' && !saveAllStagingImagesToGallery;
+ const board = tab === 'canvas' && !saveAllStagingImagesToGallery ? undefined : getBoardField(state);
return {
is_intermediate,
diff --git a/invokeai/frontend/web/src/features/ui/layouts/CanvasWorkspacePanel.tsx b/invokeai/frontend/web/src/features/ui/layouts/CanvasWorkspacePanel.tsx
index e9e4d2d0bf..3ff0ef6c2b 100644
--- a/invokeai/frontend/web/src/features/ui/layouts/CanvasWorkspacePanel.tsx
+++ b/invokeai/frontend/web/src/features/ui/layouts/CanvasWorkspacePanel.tsx
@@ -2,6 +2,7 @@ import { ContextMenu, Divider, Flex, IconButton, Menu, MenuButton, MenuList } fr
import { useAppSelector } from 'app/store/storeHooks';
import { CanvasAlertsInvocationProgress } from 'features/controlLayers/components/CanvasAlerts/CanvasAlertsInvocationProgress';
import { CanvasAlertsPreserveMask } from 'features/controlLayers/components/CanvasAlerts/CanvasAlertsPreserveMask';
+import { CanvasAlertsSaveAllStagingImagesToGallery } from 'features/controlLayers/components/CanvasAlerts/CanvasAlertsSaveAllStagingImagesToGallery';
import { CanvasAlertsSelectedEntityStatus } from 'features/controlLayers/components/CanvasAlerts/CanvasAlertsSelectedEntityStatus';
import { CanvasBusySpinner } from 'features/controlLayers/components/CanvasBusySpinner';
import { CanvasContextMenuGlobalMenuItems } from 'features/controlLayers/components/CanvasContextMenu/CanvasContextMenuGlobalMenuItems';
@@ -88,6 +89,7 @@ export const CanvasWorkspacePanel = memo(() => {
{showHUD && }
+