Skip to content

Commit 4de6549

Browse files
refactor(ui): track discarded items instead of using delete method
1 parent 368be34 commit 4de6549

File tree

3 files changed

+60
-31
lines changed

3 files changed

+60
-31
lines changed

invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/context.tsx

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { EMPTY_ARRAY } from 'app/store/constants';
44
import { useAppStore } from 'app/store/storeHooks';
55
import { buildZodTypeGuard } from 'common/util/zodUtils';
66
import { getOutputImageName } from 'features/controlLayers/components/SimpleSession/shared';
7+
import { canvasQueueItemDiscarded, selectDiscardedItems } from 'features/controlLayers/store/canvasStagingAreaSlice';
78
import type { ProgressImage } from 'features/nodes/types/common';
89
import type { Atom, MapStore, StoreValue, WritableAtom } from 'nanostores';
910
import { atom, computed, effect, map, subscribeKeys } from 'nanostores';
@@ -104,6 +105,7 @@ type CanvasSessionContextValue = {
104105
selectFirst: () => void;
105106
selectLast: () => void;
106107
onImageLoad: (itemId: number) => void;
108+
discard: (itemId: number) => void;
107109
};
108110

109111
const CanvasSessionContext = createContext<CanvasSessionContextValue | null>(null);
@@ -138,14 +140,7 @@ export const CanvasSessionContextProvider = memo(
138140
* Manually-synced atom containing queue items for the current session. This is populated from the RTK Query cache
139141
* and kept in sync with it via a redux subscription.
140142
*/
141-
const $allItems = useState(() => atom<S['SessionQueueItem'][]>([]))[0];
142-
143-
/**
144-
* All queue items for the current session, excluding canceled and failed items.
145-
*/
146-
const $items = useState(() =>
147-
computed([$allItems], (allItems) => allItems.filter(({ status }) => status !== 'canceled' && status !== 'failed'))
148-
)[0];
143+
const $items = useState(() => atom<S['SessionQueueItem'][]>([]))[0];
149144

150145
/**
151146
* Whether auto-switch is enabled.
@@ -239,12 +234,27 @@ export const CanvasSessionContextProvider = memo(
239234
*/
240235
const selectQueueItems = useMemo(
241236
() =>
242-
createSelector(queueApi.endpoints.listAllQueueItems.select({ destination: session.id }), ({ data }) => {
243-
return data ?? EMPTY_ARRAY;
244-
}),
237+
createSelector(
238+
[queueApi.endpoints.listAllQueueItems.select({ destination: session.id }), selectDiscardedItems],
239+
({ data }, discardedItems) => {
240+
if (!data) {
241+
return EMPTY_ARRAY;
242+
}
243+
return data.filter(
244+
({ status, item_id }) => status !== 'canceled' && status !== 'failed' && !discardedItems.includes(item_id)
245+
);
246+
}
247+
),
245248
[session.id]
246249
);
247250

251+
const discard = useCallback(
252+
(itemId: number) => {
253+
store.dispatch(canvasQueueItemDiscarded({ itemId }));
254+
},
255+
[store]
256+
);
257+
248258
const selectNext = useCallback(() => {
249259
const selectedItemId = $selectedItemId.get();
250260
if (selectedItemId === null) {
@@ -350,22 +360,20 @@ export const CanvasSessionContextProvider = memo(
350360

351361
// Set up state subscriptions and effects
352362
useEffect(() => {
353-
let _prevAllItems: readonly S['SessionQueueItem'][] = [];
354-
// Seed the $allItems atom with the initial query cache state
355-
$allItems.set(selectQueueItems(store.getState()));
363+
let _prevItems: readonly S['SessionQueueItem'][] = [];
364+
// Seed the $items atom with the initial query cache state
365+
$items.set(selectQueueItems(store.getState()));
356366

357-
// Manually keep the $allItems atom in sync as the query cache is updated
367+
// Manually keep the $items atom in sync as the query cache is updated
358368
const unsubReduxSyncToItemsAtom = store.subscribe(() => {
359-
const prevItems = $allItems.get();
369+
const prevItems = $items.get();
360370
const items = selectQueueItems(store.getState());
361371
if (items !== prevItems) {
362-
_prevAllItems = prevItems;
363-
$allItems.set(items);
372+
_prevItems = prevItems;
373+
$items.set(items);
364374
}
365375
});
366376

367-
let _prevItems: readonly S['SessionQueueItem'][] = [];
368-
369377
// Handle cases that could result in a nonexistent queue item being selected.
370378
const unsubEnsureSelectedItemIdExists = effect(
371379
[$items, $selectedItemId, $lastStartedItemId],
@@ -500,14 +508,13 @@ export const CanvasSessionContextProvider = memo(
500508
unsubReduxSyncToItemsAtom();
501509
unsubEnsureSelectedItemIdExists();
502510
unsubCleanUpProgressData();
503-
$allItems.set([]);
511+
$items.set([]);
504512
$progressData.set({});
505513
$selectedItemId.set(null);
506514
};
507515
}, [
508-
$allItems,
509-
$autoSwitch,
510516
$items,
517+
$autoSwitch,
511518
$lastLoadedItemId,
512519
$lastStartedItemId,
513520
$progressData,
@@ -535,6 +542,7 @@ export const CanvasSessionContextProvider = memo(
535542
selectFirst,
536543
selectLast,
537544
onImageLoad,
545+
discard,
538546
}),
539547
[
540548
$autoSwitch,
@@ -553,6 +561,7 @@ export const CanvasSessionContextProvider = memo(
553561
selectFirst,
554562
selectLast,
555563
onImageLoad,
564+
discard,
556565
]
557566
);
558567

invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarDiscardSelectedButton.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ import { useStore } from '@nanostores/react';
33
import { useAppDispatch } from 'app/store/storeHooks';
44
import { useCanvasSessionContext } from 'features/controlLayers/components/SimpleSession/context';
55
import { canvasSessionReset, generateSessionReset } from 'features/controlLayers/store/canvasStagingAreaSlice';
6-
import { useDeleteQueueItem } from 'features/queue/hooks/useDeleteQueueItem';
6+
import { useCancelQueueItem } from 'features/queue/hooks/useCancelQueueItem';
77
import { memo, useCallback } from 'react';
88
import { useTranslation } from 'react-i18next';
99
import { PiXBold } from 'react-icons/pi';
1010

1111
export const StagingAreaToolbarDiscardSelectedButton = memo(({ isDisabled }: { isDisabled?: boolean }) => {
1212
const dispatch = useAppDispatch();
1313
const ctx = useCanvasSessionContext();
14-
const deleteQueueItem = useDeleteQueueItem();
14+
const cancelQueueItem = useCancelQueueItem();
1515
const selectedItemId = useStore(ctx.$selectedItemId);
1616

1717
const { t } = useTranslation();
@@ -20,7 +20,8 @@ export const StagingAreaToolbarDiscardSelectedButton = memo(({ isDisabled }: { i
2020
if (selectedItemId === null) {
2121
return;
2222
}
23-
await deleteQueueItem.trigger(selectedItemId, { withToast: false });
23+
ctx.discard(selectedItemId);
24+
await cancelQueueItem.trigger(selectedItemId, { withToast: false });
2425
const itemCount = ctx.$itemCount.get();
2526
if (itemCount <= 1) {
2627
if (ctx.session.type === 'advanced') {
@@ -30,7 +31,7 @@ export const StagingAreaToolbarDiscardSelectedButton = memo(({ isDisabled }: { i
3031
dispatch(generateSessionReset());
3132
}
3233
}
33-
}, [selectedItemId, deleteQueueItem, ctx.$itemCount, ctx.session.type, dispatch]);
34+
}, [selectedItemId, ctx, cancelQueueItem, dispatch]);
3435

3536
return (
3637
<IconButton
@@ -40,8 +41,8 @@ export const StagingAreaToolbarDiscardSelectedButton = memo(({ isDisabled }: { i
4041
onClick={discardSelected}
4142
colorScheme="invokeBlue"
4243
fontSize={16}
43-
isDisabled={selectedItemId === null || deleteQueueItem.isDisabled || isDisabled}
44-
isLoading={deleteQueueItem.isLoading}
44+
isDisabled={selectedItemId === null || cancelQueueItem.isDisabled || isDisabled}
45+
isLoading={cancelQueueItem.isLoading}
4546
/>
4647
);
4748
});

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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import { canvasReset } from 'features/controlLayers/store/actions';
66
type CanvasStagingAreaState = {
77
generateSessionId: string | null;
88
canvasSessionId: string | null;
9+
canvasDiscardedQueueItems: number[];
910
};
1011

1112
const INITIAL_STATE: CanvasStagingAreaState = {
1213
generateSessionId: null,
1314
canvasSessionId: null,
15+
canvasDiscardedQueueItems: [],
1416
};
1517

1618
const getInitialState = (): CanvasStagingAreaState => deepClone(INITIAL_STATE);
@@ -26,12 +28,20 @@ export const canvasSessionSlice = createSlice({
2628
generateSessionReset: (state) => {
2729
state.generateSessionId = null;
2830
},
31+
canvasQueueItemDiscarded: (state, action: PayloadAction<{ itemId: number }>) => {
32+
const { itemId } = action.payload;
33+
if (!state.canvasDiscardedQueueItems.includes(itemId)) {
34+
state.canvasDiscardedQueueItems.push(itemId);
35+
}
36+
},
2937
canvasSessionIdChanged: (state, action: PayloadAction<{ id: string }>) => {
3038
const { id } = action.payload;
3139
state.canvasSessionId = id;
40+
state.canvasDiscardedQueueItems = [];
3241
},
3342
canvasSessionReset: (state) => {
3443
state.canvasSessionId = null;
44+
state.canvasDiscardedQueueItems = [];
3545
},
3646
},
3747
extraReducers(builder) {
@@ -41,8 +51,13 @@ export const canvasSessionSlice = createSlice({
4151
},
4252
});
4353

44-
export const { generateSessionIdChanged, generateSessionReset, canvasSessionIdChanged, canvasSessionReset } =
45-
canvasSessionSlice.actions;
54+
export const {
55+
generateSessionIdChanged,
56+
generateSessionReset,
57+
canvasSessionIdChanged,
58+
canvasSessionReset,
59+
canvasQueueItemDiscarded,
60+
} = canvasSessionSlice.actions;
4661

4762
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
4863
const migrate = (state: any): any => {
@@ -64,3 +79,7 @@ export const selectGenerateSessionId = createSelector(
6479
({ generateSessionId }) => generateSessionId
6580
);
6681
export const selectIsStaging = createSelector(selectCanvasSessionId, (canvasSessionId) => canvasSessionId !== null);
82+
export const selectDiscardedItems = createSelector(
83+
selectCanvasSessionSlice,
84+
({ canvasDiscardedQueueItems }) => canvasDiscardedQueueItems
85+
);

0 commit comments

Comments
 (0)