Skip to content

Commit 4e622f0

Browse files
author
Attila Cseh
committed
canvas dependencies initialization fixed
1 parent 463b105 commit 4e622f0

File tree

8 files changed

+169
-111
lines changed

8 files changed

+169
-111
lines changed

invokeai/frontend/web/src/app/store/store.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,13 @@ import { merge } from 'es-toolkit';
2222
import { omit, pick } from 'es-toolkit/compat';
2323
import { changeBoardModalSliceConfig } from 'features/changeBoardModal/store/slice';
2424
import { canvasSettingsReducer, canvasSettingsSliceConfig } from 'features/controlLayers/store/canvasSettingsSlice';
25-
import { canvasSliceConfig, migrateCanvas, undoableCanvasesReducer } from 'features/controlLayers/store/canvasSlice';
26-
import { canvasSessionSliceConfig } from 'features/controlLayers/store/canvasStagingAreaSlice';
25+
import {
26+
canvasSliceConfig,
27+
initializeCanvasDependencies,
28+
migrateCanvas,
29+
undoableCanvasesReducer,
30+
} from 'features/controlLayers/store/canvasSlice';
31+
import { canvasSessionReducer, canvasSessionSliceConfig } from 'features/controlLayers/store/canvasStagingAreaSlice';
2732
import { lorasSliceConfig } from 'features/controlLayers/store/lorasSlice';
2833
import { paramsSliceConfig, paramsSliceReducer } from 'features/controlLayers/store/paramsSlice';
2934
import { refImagesSliceConfig } from 'features/controlLayers/store/refImagesSlice';
@@ -88,7 +93,7 @@ const SLICE_CONFIGS = {
8893
// Remember to wrap undoable reducers in `undoable()`!
8994
const ALL_REDUCERS = {
9095
[api.reducerPath]: api.reducer,
91-
[canvasSessionSliceConfig.slice.reducerPath]: canvasSessionSliceConfig.slice.reducer,
96+
[canvasSessionSliceConfig.slice.reducerPath]: canvasSessionReducer,
9297
[canvasSettingsSliceConfig.slice.reducerPath]: canvasSettingsReducer,
9398
[canvasSliceConfig.slice.reducerPath]: undoableCanvasesReducer,
9499
[changeBoardModalSliceConfig.slice.reducerPath]: changeBoardModalSliceConfig.slice.reducer,
@@ -222,6 +227,7 @@ export const createStore = (options?: { persist?: boolean; persistDebounce?: num
222227
effect: (action, { dispatch, unsubscribe }) => {
223228
unsubscribe();
224229
dispatch(migrateCanvas());
230+
dispatch(initializeCanvasDependencies());
225231
options?.onRehydrated?.();
226232
},
227233
});

invokeai/frontend/web/src/features/controlLayers/store/canvasSettingsSlice.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { z } from 'zod';
1111
import {
1212
canvasAdding,
1313
canvasDeleted,
14+
canvasInitialized,
1415
canvasMultiCanvasMigrated,
1516
MIGRATION_MULTI_CANVAS_ID_PLACEHOLDER,
1617
} from './canvasSlice';
@@ -154,7 +155,7 @@ type CanvasPayloadAction<P> = PayloadAction<PayloadWithCanvasId<P>>;
154155

155156
const canvasSettingsSlice = createSlice({
156157
name: 'canvasSettings',
157-
initialState: getInitialCanvasSettingsState(),
158+
initialState: getInitialCanvasSettingsState,
158159
reducers: {
159160
settingsClipToBboxChanged: (state, action: PayloadAction<{ clipToBbox: boolean }>) => {
160161
const { clipToBbox } = action.payload;
@@ -231,10 +232,16 @@ const canvasSettingsSlice = createSlice({
231232
state.canvases[settings.canvasId] = settings;
232233
delete state.canvases[MIGRATION_MULTI_CANVAS_ID_PLACEHOLDER];
233234
});
235+
builder.addCase(canvasInitialized, (state, action) => {
236+
const canvasId = action.payload.canvasId;
237+
if (!state.canvases[canvasId]) {
238+
state.canvases[canvasId] = getInitialCanvasInstanceSettings(canvasId);
239+
}
240+
});
234241
},
235242
});
236243

237-
const canvasInstanceSettingsSlice = createSlice({
244+
const canvasInstanceSettingsFragment = createSlice({
238245
name: 'canvasSettings',
239246
initialState: {} as CanvasInstanceSettings,
240247
reducers: {
@@ -294,11 +301,14 @@ export const {
294301
settingsBgColorChanged,
295302
settingsFgColorChanged,
296303
settingsColorsSetToDefault,
297-
} = canvasInstanceSettingsSlice.actions;
304+
} = canvasInstanceSettingsFragment.actions;
298305

299-
const isCanvasInstanceSettingsAction = isAnyOf(...Object.values(canvasInstanceSettingsSlice.actions));
306+
const isCanvasInstanceSettingsAction = isAnyOf(...Object.values(canvasInstanceSettingsFragment.actions));
300307

301-
export const canvasSettingsReducer = (state: CanvasSettingsState, action: UnknownAction): CanvasSettingsState => {
308+
export const canvasSettingsReducer = (
309+
state: CanvasSettingsState | undefined,
310+
action: UnknownAction
311+
): CanvasSettingsState => {
302312
state = canvasSettingsSlice.reducer(state, action);
303313

304314
if (!isCanvasInstanceSettingsAction(action)) {
@@ -311,7 +321,7 @@ export const canvasSettingsReducer = (state: CanvasSettingsState, action: Unknow
311321
...state,
312322
canvases: {
313323
...state.canvases,
314-
[canvasId]: canvasInstanceSettingsSlice.reducer(state.canvases[canvasId], action),
324+
[canvasId]: canvasInstanceSettingsFragment.reducer(state.canvases[canvasId], action),
315325
},
316326
};
317327
};

invokeai/frontend/web/src/features/controlLayers/store/canvasSlice.ts

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,6 @@ const canvasesSlice = createSlice({
193193
},
194194
},
195195
canvasAdding: (_state, _action: CanvasPayloadAction<unknown>) => {},
196-
canvasMigrated: (state) => {
197-
delete state.migration;
198-
},
199-
canvasMultiCanvasMigrated: (_state, _action: CanvasPayloadAction<unknown>) => {},
200196
canvasActivated: (state, action: CanvasPayloadAction<unknown>) => {
201197
const { canvasId } = action.payload;
202198

@@ -227,10 +223,15 @@ const canvasesSlice = createSlice({
227223
delete state.canvases[canvas.id];
228224
},
229225
canvasDeleted: (_state, _action: CanvasPayloadAction<unknown>) => {},
226+
canvasMigrated: (state) => {
227+
delete state.migration;
228+
},
229+
canvasMultiCanvasMigrated: (_state, _action: CanvasPayloadAction<unknown>) => {},
230+
canvasInitialized: (_state, _action: CanvasPayloadAction<unknown>) => {},
230231
},
231232
});
232233

233-
const canvasSlice = createSlice({
234+
const canvasFragment = createSlice({
234235
name: 'canvas',
235236
initialState: {} as CanvasState,
236237
reducers: {
@@ -1890,6 +1891,11 @@ export const addCanvas = (payload: { isSelected?: boolean }) => (dispatch: AppDi
18901891

18911892
export const MIGRATION_MULTI_CANVAS_ID_PLACEHOLDER = 'multi-canvas-id-placeholder';
18921893

1894+
export const deleteCanvas = (payload: { canvasId: string }) => (dispatch: AppDispatch) => {
1895+
dispatch(canvasesSlice.actions.canvasDeleting(payload));
1896+
dispatch(canvasesSlice.actions.canvasDeleted(payload));
1897+
};
1898+
18931899
export const migrateCanvas = () => (dispatch: AppDispatch, getState: () => RootState) => {
18941900
const state = getState();
18951901

@@ -1900,17 +1906,19 @@ export const migrateCanvas = () => (dispatch: AppDispatch, getState: () => RootS
19001906
dispatch(canvasesSlice.actions.canvasMigrated());
19011907
};
19021908

1903-
export const deleteCanvas = (payload: { canvasId: string }) => (dispatch: AppDispatch) => {
1904-
dispatch(canvasesSlice.actions.canvasDeleting(payload));
1905-
dispatch(canvasesSlice.actions.canvasDeleted(payload));
1909+
export const initializeCanvasDependencies = () => (dispatch: AppDispatch, getState: () => RootState) => {
1910+
const state = getState();
1911+
1912+
dispatch(canvasInitialized({ canvasId: state.canvas.activeCanvasId }));
19061913
};
19071914

19081915
export const {
19091916
// Canvas
19101917
canvasAdding,
1911-
canvasMultiCanvasMigrated,
19121918
canvasDeleted,
19131919
canvasActivated,
1920+
canvasMultiCanvasMigrated,
1921+
canvasInitialized,
19141922
} = canvasesSlice.actions;
19151923

19161924
export const {
@@ -2010,9 +2018,9 @@ export const {
20102018
inpaintMaskDenoiseLimitChanged,
20112019
inpaintMaskDenoiseLimitDeleted,
20122020
// inpaintMaskRecalled,
2013-
} = canvasSlice.actions;
2021+
} = canvasFragment.actions;
20142022

2015-
const isCanvasSliceAction = isAnyOf(...Object.values(canvasSlice.actions));
2023+
const isCanvasAction = isAnyOf(...Object.values(canvasFragment.actions));
20162024

20172025
let filter = true;
20182026
const isActionFileterd = isAnyOf(canvasNameChanged, entitySelected);
@@ -2024,7 +2032,7 @@ const canvasUndoableConfig: UndoableOptions<CanvasState, UnknownAction> = {
20242032
clearHistoryType: canvasClearHistory.type,
20252033
filter: (action, _state, _history) => {
20262034
// Ignore both all actions from other slices and canvas management actions
2027-
if (!action.type.startsWith(canvasSlice.name) || isActionFileterd(action)) {
2035+
if (!action.type.startsWith(canvasFragment.name) || isActionFileterd(action)) {
20282036
return false;
20292037
}
20302038
// Throttle rapid actions of the same type
@@ -2035,15 +2043,15 @@ const canvasUndoableConfig: UndoableOptions<CanvasState, UnknownAction> = {
20352043
// debug: import.meta.env.MODE === 'development',
20362044
};
20372045

2038-
const undoableCanvasReducer = undoable(canvasSlice.reducer, canvasUndoableConfig);
2046+
const undoableCanvasReducer = undoable(canvasFragment.reducer, canvasUndoableConfig);
20392047

20402048
export const undoableCanvasesReducer = (
2041-
state: CanvasesStateWithHistory,
2049+
state: CanvasesStateWithHistory | undefined,
20422050
action: UnknownAction
20432051
): CanvasesStateWithHistory => {
20442052
state = canvasesSlice.reducer(state, action);
20452053

2046-
if (!isCanvasSliceAction(action)) {
2054+
if (!isCanvasAction(action)) {
20472055
return state;
20482056
}
20492057

invokeai/frontend/web/src/features/controlLayers/store/canvasStagingAreaSlice.ts

Lines changed: 71 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { createSelector, createSlice, type PayloadAction } from '@reduxjs/toolkit';
1+
import type { PayloadAction, UnknownAction } from '@reduxjs/toolkit';
2+
import { createSelector, createSlice, isAnyOf } from '@reduxjs/toolkit';
23
import { EMPTY_ARRAY } from 'app/store/constants';
34
import type { RootState } from 'app/store/store';
45
import type { SliceConfig } from 'app/store/types';
@@ -11,64 +12,85 @@ import z from 'zod';
1112
import {
1213
canvasAdding,
1314
canvasDeleted,
15+
canvasInitialized,
1416
canvasMultiCanvasMigrated,
1517
MIGRATION_MULTI_CANVAS_ID_PLACEHOLDER,
1618
} from './canvasSlice';
1719
import { selectActiveCanvasId } from './selectors';
1820

19-
const zCanvasSessionState = z.object({
21+
const zCanvasSession = z.object({
2022
canvasId: z.string().min(1),
2123
canvasSessionId: z.string(),
2224
canvasDiscardedQueueItems: z.array(z.number().int()),
2325
});
24-
type CanvasSessionState = z.infer<typeof zCanvasSessionState>;
26+
type CanvasSession = z.infer<typeof zCanvasSession>;
2527
const zCanvasStagingAreaState = z.object({
2628
_version: z.literal(2),
27-
sessions: z.record(z.string(), zCanvasSessionState),
29+
sessions: z.record(z.string(), zCanvasSession),
2830
});
2931
type CanvasStagingAreaState = z.infer<typeof zCanvasStagingAreaState>;
3032

3133
type CanvasPayload<T> = { canvasId: string } & T;
3234
type CanvasPayloadAction<T> = PayloadAction<CanvasPayload<T>>;
3335

34-
const getInitialCanvasSessionState = (canvasId: string): CanvasSessionState => ({
36+
const getInitialCanvasSessionState = (canvasId: string): CanvasSession => ({
3537
canvasId,
3638
canvasSessionId: getPrefixedId('canvas'),
3739
canvasDiscardedQueueItems: [],
3840
});
3941

40-
const getInitialState = (): CanvasStagingAreaState => ({
42+
const getInitialCanvasStagingAreaState = (): CanvasStagingAreaState => ({
4143
_version: 2,
4244
sessions: {},
4345
});
4446

4547
const canvasStagingAreaSlice = createSlice({
4648
name: 'canvasSession',
47-
initialState: getInitialState(),
48-
reducers: {
49-
canvasQueueItemDiscarded: (state, action: CanvasPayloadAction<{ itemId: number }>) => {
50-
const { canvasId, itemId } = action.payload;
51-
52-
const session = state.sessions[canvasId];
49+
initialState: getInitialCanvasStagingAreaState,
50+
reducers: {},
51+
extraReducers(builder) {
52+
builder.addCase(canvasAdding, (state, action) => {
53+
const session = getInitialCanvasSessionState(action.payload.canvasId);
54+
state.sessions[session.canvasId] = session;
55+
});
56+
builder.addCase(canvasDeleted, (state, action) => {
57+
delete state.sessions[action.payload.canvasId];
58+
});
59+
builder.addCase(canvasMultiCanvasMigrated, (state, action) => {
60+
const session = state.sessions[MIGRATION_MULTI_CANVAS_ID_PLACEHOLDER];
5361
if (!session) {
5462
return;
5563
}
64+
session.canvasId = action.payload.canvasId;
65+
state.sessions[session.canvasId] = session;
66+
delete state.sessions[MIGRATION_MULTI_CANVAS_ID_PLACEHOLDER];
67+
});
68+
builder.addCase(canvasInitialized, (state, action) => {
69+
const canvasId = action.payload.canvasId;
70+
if (!state.sessions[canvasId]) {
71+
state.sessions[canvasId] = getInitialCanvasSessionState(canvasId);
72+
}
73+
});
74+
},
75+
});
76+
77+
const canvasSessionFragment = createSlice({
78+
name: 'canvasSession',
79+
initialState: {} as CanvasSession,
80+
reducers: {
81+
canvasQueueItemDiscarded: (state, action: CanvasPayloadAction<{ itemId: number }>) => {
82+
const { itemId } = action.payload;
5683

57-
if (!session.canvasDiscardedQueueItems.includes(itemId)) {
58-
session.canvasDiscardedQueueItems.push(itemId);
84+
if (!state.canvasDiscardedQueueItems.includes(itemId)) {
85+
state.canvasDiscardedQueueItems.push(itemId);
5986
}
6087
},
6188
canvasSessionReset: {
6289
reducer: (state, action: CanvasPayloadAction<{ canvasSessionId: string }>) => {
63-
const { canvasId, canvasSessionId } = action.payload;
64-
65-
const session = state.sessions[canvasId];
66-
if (!session) {
67-
return;
68-
}
90+
const { canvasSessionId } = action.payload;
6991

70-
session.canvasSessionId = canvasSessionId;
71-
session.canvasDiscardedQueueItems = [];
92+
state.canvasSessionId = canvasSessionId;
93+
state.canvasDiscardedQueueItems = [];
7294
},
7395
prepare: (payload: CanvasPayload<object>) => {
7496
return {
@@ -80,32 +102,37 @@ const canvasStagingAreaSlice = createSlice({
80102
},
81103
},
82104
},
83-
extraReducers(builder) {
84-
builder.addCase(canvasAdding, (state, action) => {
85-
const session = getInitialCanvasSessionState(action.payload.canvasId);
86-
state.sessions[session.canvasId] = session;
87-
});
88-
builder.addCase(canvasDeleted, (state, action) => {
89-
delete state.sessions[action.payload.canvasId];
90-
});
91-
builder.addCase(canvasMultiCanvasMigrated, (state, action) => {
92-
const session = state.sessions[MIGRATION_MULTI_CANVAS_ID_PLACEHOLDER];
93-
if (!session) {
94-
return;
95-
}
96-
session.canvasId = action.payload.canvasId;
97-
state.sessions[session.canvasId] = session;
98-
delete state.sessions[MIGRATION_MULTI_CANVAS_ID_PLACEHOLDER];
99-
});
100-
},
101105
});
102106

103-
export const { canvasSessionReset, canvasQueueItemDiscarded } = canvasStagingAreaSlice.actions;
107+
export const { canvasSessionReset, canvasQueueItemDiscarded } = canvasSessionFragment.actions;
108+
109+
const isCanvasSessionAction = isAnyOf(...Object.values(canvasSessionFragment.actions));
110+
111+
export const canvasSessionReducer = (
112+
state: CanvasStagingAreaState | undefined,
113+
action: UnknownAction
114+
): CanvasStagingAreaState => {
115+
state = canvasStagingAreaSlice.reducer(state, action);
116+
117+
if (!isCanvasSessionAction(action)) {
118+
return state;
119+
}
120+
121+
const canvasId = action.payload.canvasId;
122+
123+
return {
124+
...state,
125+
sessions: {
126+
...state.sessions,
127+
[canvasId]: canvasSessionFragment.reducer(state.sessions[canvasId], action),
128+
},
129+
};
130+
};
104131

105132
export const canvasSessionSliceConfig: SliceConfig<typeof canvasStagingAreaSlice> = {
106133
slice: canvasStagingAreaSlice,
107134
schema: zCanvasStagingAreaState,
108-
getInitialState,
135+
getInitialState: getInitialCanvasStagingAreaState,
109136
persistConfig: {
110137
migrate: (state) => {
111138
assert(isPlainObject(state));
@@ -117,7 +144,7 @@ export const canvasSessionSliceConfig: SliceConfig<typeof canvasStagingAreaSlice
117144
const session = {
118145
canvasId: MIGRATION_MULTI_CANVAS_ID_PLACEHOLDER,
119146
...state,
120-
} as CanvasSessionState;
147+
} as CanvasSession;
121148

122149
state = {
123150
_version: 2,
@@ -130,7 +157,7 @@ export const canvasSessionSliceConfig: SliceConfig<typeof canvasStagingAreaSlice
130157
},
131158
};
132159

133-
const findSessionByCanvasId = (sessions: Record<string, CanvasSessionState>, canvasId: string) => {
160+
const findSessionByCanvasId = (sessions: Record<string, CanvasSession>, canvasId: string) => {
134161
const session = sessions[canvasId];
135162
assert(session, 'Session must exist for a canvas once the canvas has been created');
136163
return session;

0 commit comments

Comments
 (0)