From b57fa235ce00418a691207ae3386ff08ae935fb6 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sun, 9 Jul 2023 13:41:52 +1000 Subject: [PATCH] feat(ui): fix listeners for adding selection to board via dnd --- .../app/contexts/AddImageToBoardContext.tsx | 4 +- .../listeners/addBoardListeners.ts | 89 +++---------------- .../listeners/imageDropped.ts | 64 ++++++++----- .../socketio/socketInvocationComplete.ts | 16 ++-- .../gallery/components/ImageContextMenu.tsx | 21 +++-- .../src/services/api/endpoints/boardImages.ts | 21 ++--- 6 files changed, 88 insertions(+), 127 deletions(-) diff --git a/invokeai/frontend/web/src/app/contexts/AddImageToBoardContext.tsx b/invokeai/frontend/web/src/app/contexts/AddImageToBoardContext.tsx index f37f06d4b19..7351abfd37f 100644 --- a/invokeai/frontend/web/src/app/contexts/AddImageToBoardContext.tsx +++ b/invokeai/frontend/web/src/app/contexts/AddImageToBoardContext.tsx @@ -1,7 +1,7 @@ import { useDisclosure } from '@chakra-ui/react'; import { PropsWithChildren, createContext, useCallback, useState } from 'react'; +import { useAddBoardImageMutation } from 'services/api/endpoints/boardImages'; import { ImageDTO } from 'services/api/types'; -import { useAddImageToBoardMutation } from 'services/api/endpoints/boardImages'; export type ImageUsage = { isInitialImage: boolean; @@ -41,7 +41,7 @@ export const AddImageToBoardContextProvider = (props: Props) => { const [imageToMove, setImageToMove] = useState(); const { isOpen, onOpen, onClose } = useDisclosure(); - const [addImageToBoard, result] = useAddImageToBoardMutation(); + const [addImageToBoard, result] = useAddBoardImageMutation(); // Clean up after deleting or dismissing the modal const closeAndClearImageToDelete = useCallback(() => { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addBoardListeners.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addBoardListeners.ts index e67f53fd883..07125534a27 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addBoardListeners.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addBoardListeners.ts @@ -1,4 +1,3 @@ -import { createAction } from '@reduxjs/toolkit'; import { log } from 'app/logging/useLogger'; import { imageUpdatedMany, @@ -12,7 +11,7 @@ const moduleLog = log.child({ namespace: 'boards' }); export const addBoardListeners = () => { // add image to board - fulfilled startAppListening({ - matcher: boardImagesApi.endpoints.addImageToBoard.matchFulfilled, + matcher: boardImagesApi.endpoints.addBoardImage.matchFulfilled, effect: (action, { getState, dispatch }) => { const { board_id, image_name } = action.meta.arg.originalArgs; @@ -32,7 +31,7 @@ export const addBoardListeners = () => { // add image to board - rejected startAppListening({ - matcher: boardImagesApi.endpoints.addImageToBoard.matchRejected, + matcher: boardImagesApi.endpoints.addBoardImage.matchRejected, effect: (action, { getState, dispatch }) => { const { board_id, image_name } = action.meta.arg.originalArgs; @@ -45,9 +44,9 @@ export const addBoardListeners = () => { // remove image from board - fulfilled startAppListening({ - matcher: boardImagesApi.endpoints.removeImageFromBoard.matchFulfilled, + matcher: boardImagesApi.endpoints.deleteBoardImage.matchFulfilled, effect: (action, { getState, dispatch }) => { - const image_name = action.meta.arg.originalArgs; + const { image_name } = action.meta.arg.originalArgs; moduleLog.debug({ data: { image_name } }, 'Image removed from board'); @@ -62,7 +61,7 @@ export const addBoardListeners = () => { // remove image from board - rejected startAppListening({ - matcher: boardImagesApi.endpoints.removeImageFromBoard.matchRejected, + matcher: boardImagesApi.endpoints.deleteBoardImage.matchRejected, effect: (action, { getState, dispatch }) => { const image_name = action.meta.arg.originalArgs; @@ -73,61 +72,9 @@ export const addBoardListeners = () => { }, }); - // gallery selection added to board - startAppListening({ - actionCreator: gallerySelectionAddedToBoard, - effect: (action, { getState, dispatch }) => { - const { board_id } = action.payload; - const image_names = getState().gallery.selection; - dispatch( - boardImagesApi.endpoints.addManyImagesToBoard.initiate({ - board_id, - image_names, - }) - ); - }, - }); - - // gallery selection removed from board - startAppListening({ - actionCreator: gallerySelectionRemovedFromBoard, - effect: (action, { getState, dispatch }) => { - const image_names = getState().gallery.selection; - dispatch( - boardImagesApi.endpoints.removeManyImagesFromBoard.initiate(image_names) - ); - }, - }); - - // batch selection added to board - startAppListening({ - actionCreator: batchSelectionAddedToBoard, - effect: (action, { getState, dispatch }) => { - const { board_id } = action.payload; - const image_names = getState().batch.selection; - dispatch( - boardImagesApi.endpoints.addManyImagesToBoard.initiate({ - board_id, - image_names, - }) - ); - }, - }); - - // batch selection removed from board - startAppListening({ - actionCreator: batchSelectionRemovedFromBoard, - effect: (action, { getState, dispatch }) => { - const image_names = getState().batch.selection; - dispatch( - boardImagesApi.endpoints.removeManyImagesFromBoard.initiate(image_names) - ); - }, - }); - // many images added to board - fulfilled startAppListening({ - matcher: boardImagesApi.endpoints.addManyImagesToBoard.matchFulfilled, + matcher: boardImagesApi.endpoints.addManyBoardImages.matchFulfilled, effect: (action, { getState, dispatch }) => { const { board_id, image_names } = action.meta.arg.originalArgs; @@ -147,7 +94,7 @@ export const addBoardListeners = () => { // many images added to board - rejected startAppListening({ - matcher: boardImagesApi.endpoints.addManyImagesToBoard.matchRejected, + matcher: boardImagesApi.endpoints.addManyBoardImages.matchRejected, effect: (action, { getState, dispatch }) => { const { board_id, image_names } = action.meta.arg.originalArgs; @@ -160,9 +107,9 @@ export const addBoardListeners = () => { // remove many images from board - fulfilled startAppListening({ - matcher: boardImagesApi.endpoints.removeManyImagesFromBoard.matchFulfilled, + matcher: boardImagesApi.endpoints.deleteManyBoardImages.matchFulfilled, effect: (action, { getState, dispatch }) => { - const image_names = action.meta.arg.originalArgs; + const { image_names } = action.meta.arg.originalArgs; moduleLog.debug({ data: { image_names } }, 'Images removed from board'); @@ -177,7 +124,7 @@ export const addBoardListeners = () => { // remove many images from board - rejected startAppListening({ - matcher: boardImagesApi.endpoints.removeManyImagesFromBoard.matchRejected, + matcher: boardImagesApi.endpoints.deleteManyBoardImages.matchRejected, effect: (action, { getState, dispatch }) => { const image_names = action.meta.arg.originalArgs; @@ -188,19 +135,3 @@ export const addBoardListeners = () => { }, }); }; - -export const gallerySelectionAddedToBoard = createAction<{ board_id: string }>( - 'boards/gallerySelectionAddedToBoard' -); - -export const gallerySelectionRemovedFromBoard = createAction( - 'boards/gallerySelectionAddedToBoard' -); - -export const batchSelectionAddedToBoard = createAction<{ - board_id: string; -}>('boards/batchSelectionAddedToBoard'); - -export const batchSelectionRemovedFromBoard = createAction( - 'boards/batchSelectionAddedToBoard' -); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDropped.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDropped.ts index cbe695fe962..6fef595f72d 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDropped.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDropped.ts @@ -18,12 +18,6 @@ import { import { initialImageChanged } from 'features/parameters/store/generationSlice'; import { boardImagesApi } from 'services/api/endpoints/boardImages'; import { startAppListening } from '../'; -import { - batchSelectionAddedToBoard, - batchSelectionRemovedFromBoard, - gallerySelectionAddedToBoard, - gallerySelectionRemovedFromBoard, -} from './addBoardListeners'; const moduleLog = log.child({ namespace: 'dnd' }); @@ -39,6 +33,11 @@ export const addImageDroppedListener = () => { const { activeData, overData } = action.payload; const state = getState(); + moduleLog.debug( + { data: { activeData, overData } }, + 'Image or selection dropped' + ); + // set current image if ( overData.actionType === 'SET_CURRENT_IMAGE' && @@ -157,7 +156,7 @@ export const addImageDroppedListener = () => { const { image_name } = activeData.payload.imageDTO; const { boardId } = overData.context; dispatch( - boardImagesApi.endpoints.addImageToBoard.initiate({ + boardImagesApi.endpoints.addBoardImage.initiate({ image_name, board_id: boardId, }) @@ -173,45 +172,70 @@ export const addImageDroppedListener = () => { ) { const { image_name } = activeData.payload.imageDTO; dispatch( - boardImagesApi.endpoints.removeImageFromBoard.initiate(image_name) + boardImagesApi.endpoints.deleteBoardImage.initiate({ image_name }) ); } - // add multiple images to board + // add gallery selection to board if ( overData.actionType === 'MOVE_BOARD' && activeData.payloadType === 'GALLERY_SELECTION' && overData.context.boardId ) { + console.log('adding gallery selection to board'); const board_id = overData.context.boardId; - dispatch(gallerySelectionAddedToBoard({ board_id })); + const image_names = state.gallery.selection; + dispatch( + boardImagesApi.endpoints.addManyBoardImages.initiate({ + board_id, + image_names, + }) + ); } + // remove gallery selection from board if ( overData.actionType === 'MOVE_BOARD' && - activeData.payloadType === 'BATCH_SELECTION' && - overData.context.boardId + activeData.payloadType === 'GALLERY_SELECTION' && + overData.context.boardId === null ) { - const board_id = overData.context.boardId; - dispatch(batchSelectionAddedToBoard({ board_id })); + console.log('removing gallery selection to board'); + const image_names = state.gallery.selection; + dispatch( + boardImagesApi.endpoints.deleteManyBoardImages.initiate({ + image_names, + }) + ); } - // remove multiple images from board + // add batch selection to board if ( overData.actionType === 'MOVE_BOARD' && - activeData.payloadType === 'GALLERY_SELECTION' && - overData.context.boardId === null + activeData.payloadType === 'BATCH_SELECTION' && + overData.context.boardId ) { - dispatch(gallerySelectionRemovedFromBoard()); + const board_id = overData.context.boardId; + const image_names = state.batch.selection; + dispatch( + boardImagesApi.endpoints.addManyBoardImages.initiate({ + board_id, + image_names, + }) + ); } - // remove multiple images from board + // remove batch selection from board if ( overData.actionType === 'MOVE_BOARD' && activeData.payloadType === 'BATCH_SELECTION' && overData.context.boardId === null ) { - dispatch(batchSelectionRemovedFromBoard()); + const image_names = state.batch.selection; + dispatch( + boardImagesApi.endpoints.deleteManyBoardImages.initiate({ + image_names, + }) + ); } }, }); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationComplete.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationComplete.ts index 3686816d5c0..6bffbe7ca03 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationComplete.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationComplete.ts @@ -1,15 +1,15 @@ -import { addImageToStagingArea } from 'features/canvas/store/canvasSlice'; -import { startAppListening } from '../..'; import { log } from 'app/logging/useLogger'; +import { addImageToStagingArea } from 'features/canvas/store/canvasSlice'; +import { progressImageSet } from 'features/system/store/systemSlice'; +import { boardImagesApi } from 'services/api/endpoints/boardImages'; +import { isImageOutput } from 'services/api/guards'; +import { imageMetadataReceived } from 'services/api/thunks/image'; +import { sessionCanceled } from 'services/api/thunks/session'; import { appSocketInvocationComplete, socketInvocationComplete, } from 'services/events/actions'; -import { imageMetadataReceived } from 'services/api/thunks/image'; -import { sessionCanceled } from 'services/api/thunks/session'; -import { isImageOutput } from 'services/api/guards'; -import { progressImageSet } from 'features/system/store/systemSlice'; -import { boardImagesApi } from 'services/api/endpoints/boardImages'; +import { startAppListening } from '../..'; const moduleLog = log.child({ namespace: 'socketio' }); const nodeDenylist = ['dataURL_image']; @@ -61,7 +61,7 @@ export const addInvocationCompleteEventListener = () => { if (boardIdToAddTo && !imageDTO.is_intermediate) { dispatch( - boardImagesApi.endpoints.addImageToBoard.initiate({ + boardImagesApi.endpoints.addBoardImage.initiate({ board_id: boardIdToAddTo, image_name, }) diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu.tsx index 0a5abc049a2..9664b7ddda0 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu.tsx @@ -29,7 +29,7 @@ import { FaTrash, } from 'react-icons/fa'; import { IoArrowUndoCircleOutline } from 'react-icons/io5'; -import { useRemoveImageFromBoardMutation } from 'services/api/endpoints/boardImages'; +import { useDeleteBoardImageMutation } from 'services/api/endpoints/boardImages'; import { ImageDTO } from 'services/api/types'; import { AddImageToBoardContext } from '../../../app/contexts/AddImageToBoardContext'; import { sentImageToCanvas, sentImageToImg2Img } from '../store/actions'; @@ -75,7 +75,7 @@ const ImageContextMenu = ({ image, children }: Props) => { const { recallBothPrompts, recallSeed, recallAllParameters } = useRecallParameters(); - const [removeFromBoard] = useRemoveImageFromBoardMutation(); + const [deleteBoardImage] = useDeleteBoardImageMutation(); // Recall parameters handlers const handleRecallPrompt = useCallback(() => { @@ -133,16 +133,16 @@ const ImageContextMenu = ({ image, children }: Props) => { if (!image.board_id) { return; } - removeFromBoard(image.image_name); - }, [image.board_id, image.image_name, removeFromBoard]); + deleteBoardImage({ image_name: image.image_name }); + }, [deleteBoardImage, image.board_id, image.image_name]); const handleAddSelectionToBoard = useCallback(() => { onClickAddToBoard(image); }, [image, onClickAddToBoard]); const handleRemoveSelectionFromBoard = useCallback(() => { - removeFromBoard(image.image_name); - }, [image.image_name, removeFromBoard]); + deleteBoardImage({ image_name: image.image_name }); + }, [deleteBoardImage, image.image_name]); const handleOpenInNewTab = () => { window.open(image.image_url, '_blank'); @@ -255,12 +255,17 @@ const ImageContextMenu = ({ image, children }: Props) => { ) : ( <> } - onClickCapture={handleAddToBoard} + onClickCapture={handleAddSelectionToBoard} > Move Selection to Board + } + onClickCapture={handleRemoveSelectionFromBoard} + > + Reset Board for Selection + } onClickCapture={handleAddSelectionToBatch} diff --git a/invokeai/frontend/web/src/services/api/endpoints/boardImages.ts b/invokeai/frontend/web/src/services/api/endpoints/boardImages.ts index c6563f3fef9..d70b963c383 100644 --- a/invokeai/frontend/web/src/services/api/endpoints/boardImages.ts +++ b/invokeai/frontend/web/src/services/api/endpoints/boardImages.ts @@ -41,7 +41,7 @@ export const boardImagesApi = api.injectEndpoints({ * Board Images Mutations */ - addImageToBoard: build.mutation({ + addBoardImage: build.mutation({ query: ({ board_id, image_name }) => ({ url: `board_images/`, method: 'POST', @@ -67,7 +67,7 @@ export const boardImagesApi = api.injectEndpoints({ }, }), - addManyImagesToBoard: build.mutation< + addManyBoardImages: build.mutation< string[], { board_id: string; image_names: string[] } >({ @@ -106,7 +106,7 @@ export const boardImagesApi = api.injectEndpoints({ }, }), - removeImageFromBoard: build.mutation({ + deleteBoardImage: build.mutation({ query: (image_name) => ({ url: `board_images/`, method: 'DELETE', @@ -115,7 +115,7 @@ export const boardImagesApi = api.injectEndpoints({ invalidatesTags: (result, error, arg) => [ { type: 'Board', id: LIST_TAG }, ], - async onQueryStarted(image_name, { dispatch, queryFulfilled }) { + async onQueryStarted({ image_name }, { dispatch, queryFulfilled }) { const patchResult = dispatch( imagesApi.util.updateQueryData('getImageDTO', image_name, (draft) => { Object.assign(draft, { board_id: null }); @@ -129,8 +129,8 @@ export const boardImagesApi = api.injectEndpoints({ }, }), - removeManyImagesFromBoard: build.mutation({ - query: (image_names) => ({ + deleteManyBoardImages: build.mutation({ + query: ({ image_names }) => ({ url: `board_images/images`, method: 'POST', body: image_names, @@ -138,7 +138,7 @@ export const boardImagesApi = api.injectEndpoints({ invalidatesTags: (result, error, arg) => [ { type: 'Board', id: LIST_TAG }, ], - async onQueryStarted(image_names, { dispatch, queryFulfilled }) { + async onQueryStarted({ image_names }, { dispatch, queryFulfilled }) { const patches: PatchCollection[] = []; image_names.forEach((n) => { @@ -161,7 +161,8 @@ export const boardImagesApi = api.injectEndpoints({ }); export const { - useAddImageToBoardMutation, - useRemoveImageFromBoardMutation, - useListBoardImagesQuery, + useAddBoardImageMutation, + useAddManyBoardImagesMutation, + useDeleteBoardImageMutation, + useDeleteManyBoardImagesMutation, } = boardImagesApi;