From 171a4e6d8091b4b6354cb7b29d87e59c878659ea Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Mon, 29 Jul 2024 10:05:42 +1000 Subject: [PATCH] fix(ui): race condition when deleting a board and resetting selected/auto-add We were checking the selected and auto-add board ids against the query cache to see if they still exist. If not, we reset. This only works if the query cache is updated by the time we do the check - race condition! We already have the board id from the query args, so there's no need to check the query cache - just compare the deleted board ID directly. Previously this file's several listeners were all in a single one and I had adapted/split its logic up a bit wonkily, introducing these problems. --- .../addArchivedOrDeletedBoardListener.ts | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addArchivedOrDeletedBoardListener.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addArchivedOrDeletedBoardListener.ts index d71ee7501b..23d3cbc9af 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addArchivedOrDeletedBoardListener.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addArchivedOrDeletedBoardListener.ts @@ -10,32 +10,32 @@ import { import { boardsApi } from 'services/api/endpoints/boards'; import { imagesApi } from 'services/api/endpoints/images'; +// Type inference doesn't work for this if you inline it in the listener for some reason +const matchAnyBoardDeleted = isAnyOf( + imagesApi.endpoints.deleteBoard.matchFulfilled, + imagesApi.endpoints.deleteBoardAndImages.matchFulfilled +); + export const addArchivedOrDeletedBoardListener = (startAppListening: AppStartListening) => { /** * The auto-add board shouldn't be set to an archived board or deleted board. When we archive a board, delete * a board, or change a the archived board visibility flag, we may need to reset the auto-add board. */ startAppListening({ - matcher: isAnyOf( - // If a board is deleted, we'll need to reset the auto-add board - imagesApi.endpoints.deleteBoard.matchFulfilled, - imagesApi.endpoints.deleteBoardAndImages.matchFulfilled - ), + matcher: matchAnyBoardDeleted, effect: async (action, { dispatch, getState }) => { const state = getState(); - const queryArgs = selectListBoardsQueryArgs(state); - const queryResult = boardsApi.endpoints.listAllBoards.select(queryArgs)(state); + const deletedBoardId = action.meta.arg.originalArgs; const { autoAddBoardId, selectedBoardId } = state.gallery; - if (!queryResult.data) { - return; - } - - if (!queryResult.data.find((board) => board.board_id === selectedBoardId)) { + // If the deleted board was currently selected, we should reset the selected board to uncategorized + if (deletedBoardId === selectedBoardId) { dispatch(boardIdSelected({ boardId: 'none' })); dispatch(galleryViewChanged('images')); } - if (!queryResult.data.find((board) => board.board_id === autoAddBoardId)) { + + // If the deleted board was selected for auto-add, we should reset the auto-add board to uncategorized + if (deletedBoardId === autoAddBoardId) { dispatch(autoAddBoardIdChanged('none')); } }, @@ -46,14 +46,8 @@ export const addArchivedOrDeletedBoardListener = (startAppListening: AppStartLis matcher: boardsApi.endpoints.updateBoard.matchFulfilled, effect: async (action, { dispatch, getState }) => { const state = getState(); - const queryArgs = selectListBoardsQueryArgs(state); - const queryResult = boardsApi.endpoints.listAllBoards.select(queryArgs)(state); const { shouldShowArchivedBoards } = state.gallery; - if (!queryResult.data) { - return; - } - const wasArchived = action.meta.arg.originalArgs.changes.archived === true; if (wasArchived && !shouldShowArchivedBoards) {