mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
(wip) delete images along with board
This commit is contained in:
parent
45935caf1d
commit
ba67e57a7e
@ -25,6 +25,7 @@ import DeleteImageModal from 'features/gallery/components/DeleteImageModal';
|
|||||||
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
|
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
|
||||||
import UpdateImageBoardModal from '../../features/gallery/components/Boards/UpdateImageBoardModal';
|
import UpdateImageBoardModal from '../../features/gallery/components/Boards/UpdateImageBoardModal';
|
||||||
import { useListModelsQuery } from 'services/api/endpoints/models';
|
import { useListModelsQuery } from 'services/api/endpoints/models';
|
||||||
|
import DeleteBoardImagesModal from '../../features/gallery/components/Boards/DeleteBoardImagesModal';
|
||||||
|
|
||||||
const DEFAULT_CONFIG = {};
|
const DEFAULT_CONFIG = {};
|
||||||
|
|
||||||
@ -158,6 +159,7 @@ const App = ({
|
|||||||
</Grid>
|
</Grid>
|
||||||
<DeleteImageModal />
|
<DeleteImageModal />
|
||||||
<UpdateImageBoardModal />
|
<UpdateImageBoardModal />
|
||||||
|
<DeleteBoardImagesModal />
|
||||||
<Toaster />
|
<Toaster />
|
||||||
<GlobalHotkeys />
|
<GlobalHotkeys />
|
||||||
</>
|
</>
|
||||||
|
@ -24,6 +24,7 @@ import {
|
|||||||
import UpdateImageBoardModal from '../../features/gallery/components/Boards/UpdateImageBoardModal';
|
import UpdateImageBoardModal from '../../features/gallery/components/Boards/UpdateImageBoardModal';
|
||||||
import { AddImageToBoardContextProvider } from '../contexts/AddImageToBoardContext';
|
import { AddImageToBoardContextProvider } from '../contexts/AddImageToBoardContext';
|
||||||
import { $authToken, $baseUrl } from 'services/api/client';
|
import { $authToken, $baseUrl } from 'services/api/client';
|
||||||
|
import { DeleteBoardImagesContextProvider } from '../contexts/DeleteBoardImagesContext';
|
||||||
|
|
||||||
const App = lazy(() => import('./App'));
|
const App = lazy(() => import('./App'));
|
||||||
const ThemeLocaleProvider = lazy(() => import('./ThemeLocaleProvider'));
|
const ThemeLocaleProvider = lazy(() => import('./ThemeLocaleProvider'));
|
||||||
@ -86,11 +87,13 @@ const InvokeAIUI = ({
|
|||||||
<ImageDndContext>
|
<ImageDndContext>
|
||||||
<DeleteImageContextProvider>
|
<DeleteImageContextProvider>
|
||||||
<AddImageToBoardContextProvider>
|
<AddImageToBoardContextProvider>
|
||||||
<App
|
<DeleteBoardImagesContextProvider>
|
||||||
config={config}
|
<App
|
||||||
headerComponent={headerComponent}
|
config={config}
|
||||||
setIsReady={setIsReady}
|
headerComponent={headerComponent}
|
||||||
/>
|
setIsReady={setIsReady}
|
||||||
|
/>
|
||||||
|
</DeleteBoardImagesContextProvider>
|
||||||
</AddImageToBoardContextProvider>
|
</AddImageToBoardContextProvider>
|
||||||
</DeleteImageContextProvider>
|
</DeleteImageContextProvider>
|
||||||
</ImageDndContext>
|
</ImageDndContext>
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
import { useDisclosure } from '@chakra-ui/react';
|
||||||
|
import { PropsWithChildren, createContext, useCallback, useState } from 'react';
|
||||||
|
import { BoardDTO } from 'services/api/types';
|
||||||
|
import { useDeleteBoardMutation } from '../../services/api/endpoints/boards';
|
||||||
|
|
||||||
|
export type ImageUsage = {
|
||||||
|
isInitialImage: boolean;
|
||||||
|
isCanvasImage: boolean;
|
||||||
|
isNodesImage: boolean;
|
||||||
|
isControlNetImage: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
type DeleteBoardImagesContextValue = {
|
||||||
|
/**
|
||||||
|
* Whether the move image dialog is open.
|
||||||
|
*/
|
||||||
|
isOpen: boolean;
|
||||||
|
/**
|
||||||
|
* Closes the move image dialog.
|
||||||
|
*/
|
||||||
|
onClose: () => void;
|
||||||
|
/**
|
||||||
|
* The image pending movement
|
||||||
|
*/
|
||||||
|
board?: BoardDTO;
|
||||||
|
onClickDeleteBoardImages: (board: BoardDTO) => void;
|
||||||
|
handleDeleteBoardImages: (boardId: string) => void;
|
||||||
|
handleDeleteBoardOnly: (boardId: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DeleteBoardImagesContext =
|
||||||
|
createContext<DeleteBoardImagesContextValue>({
|
||||||
|
isOpen: false,
|
||||||
|
onClose: () => undefined,
|
||||||
|
onClickDeleteBoardImages: () => undefined,
|
||||||
|
handleDeleteBoardImages: () => undefined,
|
||||||
|
handleDeleteBoardOnly: () => undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
type Props = PropsWithChildren;
|
||||||
|
|
||||||
|
export const DeleteBoardImagesContextProvider = (props: Props) => {
|
||||||
|
const [boardToDelete, setBoardToDelete] = useState<BoardDTO>();
|
||||||
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
|
|
||||||
|
const [deleteBoardAndImages] = useDeleteBoardAndImagesMutation();
|
||||||
|
const [deleteBoard] = useDeleteBoardMutation();
|
||||||
|
|
||||||
|
// Clean up after deleting or dismissing the modal
|
||||||
|
const closeAndClearBoardToDelete = useCallback(() => {
|
||||||
|
setBoardToDelete(undefined);
|
||||||
|
onClose();
|
||||||
|
}, [onClose]);
|
||||||
|
|
||||||
|
const onClickDeleteBoardImages = useCallback(
|
||||||
|
(board?: BoardDTO) => {
|
||||||
|
console.log({ board });
|
||||||
|
if (!board) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setBoardToDelete(board);
|
||||||
|
onOpen();
|
||||||
|
},
|
||||||
|
[setBoardToDelete, onOpen]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleDeleteBoardImages = useCallback(
|
||||||
|
(boardId: string) => {
|
||||||
|
if (boardToDelete) {
|
||||||
|
deleteBoardAndImages(boardId);
|
||||||
|
closeAndClearBoardToDelete();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[deleteBoardAndImages, closeAndClearBoardToDelete, boardToDelete]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleDeleteBoardOnly = useCallback(
|
||||||
|
(boardId: string) => {
|
||||||
|
if (boardToDelete) {
|
||||||
|
deleteBoard(boardId);
|
||||||
|
closeAndClearBoardToDelete();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[deleteBoard, closeAndClearBoardToDelete, boardToDelete]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DeleteBoardImagesContext.Provider
|
||||||
|
value={{
|
||||||
|
isOpen,
|
||||||
|
board: boardToDelete,
|
||||||
|
onClose: closeAndClearBoardToDelete,
|
||||||
|
onClickDeleteBoardImages,
|
||||||
|
handleDeleteBoardImages,
|
||||||
|
handleDeleteBoardOnly,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</DeleteBoardImagesContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,78 @@
|
|||||||
|
import {
|
||||||
|
AlertDialog,
|
||||||
|
AlertDialogBody,
|
||||||
|
AlertDialogContent,
|
||||||
|
AlertDialogFooter,
|
||||||
|
AlertDialogHeader,
|
||||||
|
AlertDialogOverlay,
|
||||||
|
Divider,
|
||||||
|
Flex,
|
||||||
|
Text,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import IAIButton from 'common/components/IAIButton';
|
||||||
|
import { memo, useContext, useRef } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { DeleteBoardImagesContext } from '../../../../app/contexts/DeleteBoardImagesContext';
|
||||||
|
|
||||||
|
const DeleteBoardImagesModal = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const {
|
||||||
|
isOpen,
|
||||||
|
onClose,
|
||||||
|
board,
|
||||||
|
handleDeleteBoardImages,
|
||||||
|
handleDeleteBoardOnly,
|
||||||
|
} = useContext(DeleteBoardImagesContext);
|
||||||
|
|
||||||
|
const cancelRef = useRef<HTMLButtonElement>(null);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AlertDialog
|
||||||
|
isOpen={isOpen}
|
||||||
|
leastDestructiveRef={cancelRef}
|
||||||
|
onClose={onClose}
|
||||||
|
isCentered
|
||||||
|
>
|
||||||
|
<AlertDialogOverlay>
|
||||||
|
{board && (
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader fontSize="lg" fontWeight="bold">
|
||||||
|
Delete Board
|
||||||
|
</AlertDialogHeader>
|
||||||
|
|
||||||
|
<AlertDialogBody>
|
||||||
|
<Flex direction="column" gap={3}>
|
||||||
|
<Divider />
|
||||||
|
<Text>{t('common.areYouSure')}</Text>
|
||||||
|
<Text fontWeight="bold">
|
||||||
|
This board has {board.image_count} image(s) that will be
|
||||||
|
deleted.
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
</AlertDialogBody>
|
||||||
|
<AlertDialogFooter gap={3}>
|
||||||
|
<IAIButton ref={cancelRef} onClick={onClose}>
|
||||||
|
Cancel
|
||||||
|
</IAIButton>
|
||||||
|
<IAIButton
|
||||||
|
colorScheme="warning"
|
||||||
|
onClick={() => handleDeleteBoardOnly(board.board_id)}
|
||||||
|
>
|
||||||
|
Delete Board Only
|
||||||
|
</IAIButton>
|
||||||
|
<IAIButton
|
||||||
|
colorScheme="error"
|
||||||
|
onClick={() => handleDeleteBoardImages(board.board_id)}
|
||||||
|
>
|
||||||
|
Delete Board and Images
|
||||||
|
</IAIButton>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
)}
|
||||||
|
</AlertDialogOverlay>
|
||||||
|
</AlertDialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(DeleteBoardImagesModal);
|
@ -11,7 +11,7 @@ import {
|
|||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
|
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback, useContext } from 'react';
|
||||||
import { FaFolder, FaTrash } from 'react-icons/fa';
|
import { FaFolder, FaTrash } from 'react-icons/fa';
|
||||||
import { ContextMenu } from 'chakra-ui-contextmenu';
|
import { ContextMenu } from 'chakra-ui-contextmenu';
|
||||||
import { BoardDTO, ImageDTO } from 'services/api/types';
|
import { BoardDTO, ImageDTO } from 'services/api/types';
|
||||||
@ -29,6 +29,7 @@ import { useDroppable } from '@dnd-kit/core';
|
|||||||
import { AnimatePresence } from 'framer-motion';
|
import { AnimatePresence } from 'framer-motion';
|
||||||
import IAIDropOverlay from 'common/components/IAIDropOverlay';
|
import IAIDropOverlay from 'common/components/IAIDropOverlay';
|
||||||
import { SelectedItemOverlay } from '../SelectedItemOverlay';
|
import { SelectedItemOverlay } from '../SelectedItemOverlay';
|
||||||
|
import { DeleteBoardImagesContext } from '../../../../app/contexts/DeleteBoardImagesContext';
|
||||||
|
|
||||||
interface HoverableBoardProps {
|
interface HoverableBoardProps {
|
||||||
board: BoardDTO;
|
board: BoardDTO;
|
||||||
@ -44,6 +45,8 @@ const HoverableBoard = memo(({ board, isSelected }: HoverableBoardProps) => {
|
|||||||
|
|
||||||
const { board_name, board_id } = board;
|
const { board_name, board_id } = board;
|
||||||
|
|
||||||
|
const { onClickDeleteBoardImages } = useContext(DeleteBoardImagesContext);
|
||||||
|
|
||||||
const handleSelectBoard = useCallback(() => {
|
const handleSelectBoard = useCallback(() => {
|
||||||
dispatch(boardIdSelected(board_id));
|
dispatch(boardIdSelected(board_id));
|
||||||
}, [board_id, dispatch]);
|
}, [board_id, dispatch]);
|
||||||
@ -65,6 +68,11 @@ const HoverableBoard = memo(({ board, isSelected }: HoverableBoardProps) => {
|
|||||||
deleteBoard(board_id);
|
deleteBoard(board_id);
|
||||||
}, [board_id, deleteBoard]);
|
}, [board_id, deleteBoard]);
|
||||||
|
|
||||||
|
const handleDeleteBoardAndImages = useCallback(() => {
|
||||||
|
console.log({ board });
|
||||||
|
onClickDeleteBoardImages(board);
|
||||||
|
}, [board, onClickDeleteBoardImages]);
|
||||||
|
|
||||||
const handleDrop = useCallback(
|
const handleDrop = useCallback(
|
||||||
(droppedImage: ImageDTO) => {
|
(droppedImage: ImageDTO) => {
|
||||||
if (droppedImage.board_id === board_id) {
|
if (droppedImage.board_id === board_id) {
|
||||||
@ -92,6 +100,15 @@ const HoverableBoard = memo(({ board, isSelected }: HoverableBoardProps) => {
|
|||||||
menuProps={{ size: 'sm', isLazy: true }}
|
menuProps={{ size: 'sm', isLazy: true }}
|
||||||
renderMenu={() => (
|
renderMenu={() => (
|
||||||
<MenuList sx={{ visibility: 'visible !important' }}>
|
<MenuList sx={{ visibility: 'visible !important' }}>
|
||||||
|
{board.image_count > 0 && (
|
||||||
|
<MenuItem
|
||||||
|
sx={{ color: 'error.300' }}
|
||||||
|
icon={<FaTrash />}
|
||||||
|
onClickCapture={handleDeleteBoardAndImages}
|
||||||
|
>
|
||||||
|
Delete Board and Images
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
<MenuItem
|
<MenuItem
|
||||||
sx={{ color: 'error.300' }}
|
sx={{ color: 'error.300' }}
|
||||||
icon={<FaTrash />}
|
icon={<FaTrash />}
|
||||||
|
@ -82,11 +82,14 @@ export const boardsApi = api.injectEndpoints({
|
|||||||
{ type: 'Board', id: arg.board_id },
|
{ type: 'Board', id: arg.board_id },
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
deleteBoard: build.mutation<void, string>({
|
deleteBoard: build.mutation<void, string>({
|
||||||
query: (board_id) => ({ url: `boards/${board_id}`, method: 'DELETE' }),
|
query: (board_id) => ({ url: `boards/${board_id}`, method: 'DELETE' }),
|
||||||
invalidatesTags: (result, error, arg) => [{ type: 'Board', id: arg }],
|
invalidatesTags: (result, error, arg) => [{ type: 'Board', id: arg }],
|
||||||
}),
|
}),
|
||||||
|
deleteBoardAndImages: build.mutation<void, string>({
|
||||||
|
query: (board_id) => ({ url: `boards/${board_id}`, method: 'DELETE', params: { include_images: true } }),
|
||||||
|
invalidatesTags: (result, error, arg) => [{ type: 'Board', id: arg }, { type: 'Image', id: LIST_TAG }],
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -96,4 +99,5 @@ export const {
|
|||||||
useCreateBoardMutation,
|
useCreateBoardMutation,
|
||||||
useUpdateBoardMutation,
|
useUpdateBoardMutation,
|
||||||
useDeleteBoardMutation,
|
useDeleteBoardMutation,
|
||||||
|
useDeleteBoardAndImagesMutation
|
||||||
} = boardsApi;
|
} = boardsApi;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user