mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Maryhipp/dummy bulk download (#4852)
* UI for bulk downloading boards or groups of images * placeholder route for bulk downloads that does nothing * lint --------- Co-authored-by: Mary Hipp <maryhipp@Marys-MacBook-Air.local>
This commit is contained in:
parent
40f9e49b5e
commit
69937d68d2
@ -322,3 +322,20 @@ async def unstar_images_in_list(
|
||||
return ImagesUpdatedFromListResult(updated_image_names=updated_image_names)
|
||||
except Exception:
|
||||
raise HTTPException(status_code=500, detail="Failed to unstar images")
|
||||
|
||||
|
||||
class ImagesDownloaded(BaseModel):
|
||||
response: Optional[str] = Field(
|
||||
description="If defined, the message to display to the user when images begin downloading"
|
||||
)
|
||||
|
||||
|
||||
@images_router.post("/download", operation_id="download_images_from_list", response_model=ImagesDownloaded)
|
||||
async def download_images_from_list(
|
||||
image_names: list[str] = Body(description="The list of names of images to download", embed=True),
|
||||
board_id: Optional[str] = Body(
|
||||
default=None, description="The board from which image should be downloaded from", embed=True
|
||||
),
|
||||
) -> ImagesDownloaded:
|
||||
# return ImagesDownloaded(response="Your images are downloading")
|
||||
raise HTTPException(status_code=501, detail="Endpoint is not yet implemented")
|
||||
|
@ -38,7 +38,8 @@
|
||||
"searchBoard": "Search Boards...",
|
||||
"selectBoard": "Select a Board",
|
||||
"topMessage": "This board contains images used in the following features:",
|
||||
"uncategorized": "Uncategorized"
|
||||
"uncategorized": "Uncategorized",
|
||||
"downloadBoard": "Download Board"
|
||||
},
|
||||
"common": {
|
||||
"accept": "Accept",
|
||||
@ -323,7 +324,10 @@
|
||||
"showUploads": "Show Uploads",
|
||||
"singleColumnLayout": "Single Column Layout",
|
||||
"unableToLoad": "Unable to load Gallery",
|
||||
"uploads": "Uploads"
|
||||
"uploads": "Uploads",
|
||||
"downloadSelection": "Download Selection",
|
||||
"preparingDownload": "Preparing Download",
|
||||
"preparingDownloadFailed": "Problem Preparing Download"
|
||||
},
|
||||
"hotkeys": {
|
||||
"acceptStagingImage": {
|
||||
|
@ -22,7 +22,8 @@ export type AppFeature =
|
||||
| 'pauseQueue'
|
||||
| 'resumeQueue'
|
||||
| 'prependQueue'
|
||||
| 'invocationCache';
|
||||
| 'invocationCache'
|
||||
| 'bulkDownload';
|
||||
|
||||
/**
|
||||
* A disable-able Stable Diffusion feature
|
||||
|
@ -11,12 +11,15 @@ import { autoAddBoardIdChanged } from 'features/gallery/store/gallerySlice';
|
||||
import { BoardId } from 'features/gallery/store/types';
|
||||
import { MouseEvent, memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaPlus } from 'react-icons/fa';
|
||||
import { FaDownload, FaPlus } from 'react-icons/fa';
|
||||
import { useBoardName } from 'services/api/hooks/useBoardName';
|
||||
import { BoardDTO } from 'services/api/types';
|
||||
import { menuListMotionProps } from 'theme/components/menu';
|
||||
import GalleryBoardContextMenuItems from './GalleryBoardContextMenuItems';
|
||||
import NoBoardContextMenuItems from './NoBoardContextMenuItems';
|
||||
import { useFeatureStatus } from '../../../system/hooks/useFeatureStatus';
|
||||
import { useBulkDownloadImagesMutation } from '../../../../services/api/endpoints/images';
|
||||
import { addToast } from '../../../system/store/systemSlice';
|
||||
|
||||
type Props = {
|
||||
board?: BoardDTO;
|
||||
@ -31,6 +34,7 @@ const BoardContextMenu = ({
|
||||
setBoardToDelete,
|
||||
children,
|
||||
}: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const selector = useMemo(
|
||||
@ -49,17 +53,43 @@ const BoardContextMenu = ({
|
||||
|
||||
const { isAutoAdd, autoAssignBoardOnClick } = useAppSelector(selector);
|
||||
const boardName = useBoardName(board_id);
|
||||
const isBulkDownloadEnabled =
|
||||
useFeatureStatus('bulkDownload').isFeatureEnabled;
|
||||
|
||||
const [bulkDownload] = useBulkDownloadImagesMutation();
|
||||
|
||||
const handleSetAutoAdd = useCallback(() => {
|
||||
dispatch(autoAddBoardIdChanged(board_id));
|
||||
}, [board_id, dispatch]);
|
||||
|
||||
const handleBulkDownload = useCallback(async () => {
|
||||
try {
|
||||
const response = await bulkDownload({
|
||||
image_names: [],
|
||||
board_id: board_id,
|
||||
}).unwrap();
|
||||
|
||||
dispatch(
|
||||
addToast({
|
||||
title: t('gallery.preparingDownload'),
|
||||
status: 'success',
|
||||
...(response.response ? { description: response.response } : {}),
|
||||
})
|
||||
);
|
||||
} catch {
|
||||
dispatch(
|
||||
addToast({
|
||||
title: t('gallery.preparingDownloadFailed'),
|
||||
status: 'error',
|
||||
})
|
||||
);
|
||||
}
|
||||
}, [t, board_id, bulkDownload, dispatch]);
|
||||
|
||||
const skipEvent = useCallback((e: MouseEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
}, []);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<IAIContextMenu<HTMLDivElement>
|
||||
menuProps={{ size: 'sm', isLazy: true }}
|
||||
@ -81,6 +111,14 @@ const BoardContextMenu = ({
|
||||
>
|
||||
{t('boards.menuItemAutoAdd')}
|
||||
</MenuItem>
|
||||
{isBulkDownloadEnabled && (
|
||||
<MenuItem
|
||||
icon={<FaDownload />}
|
||||
onClickCapture={handleBulkDownload}
|
||||
>
|
||||
{t('boards.downloadBoard')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{!board && <NoBoardContextMenuItems />}
|
||||
{board && (
|
||||
<GalleryBoardContextMenuItems
|
||||
|
@ -8,20 +8,29 @@ import {
|
||||
} from 'features/changeBoardModal/store/slice';
|
||||
import { imagesToDeleteSelected } from 'features/deleteImageModal/store/slice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { FaFolder, FaTrash } from 'react-icons/fa';
|
||||
import { FaDownload, FaFolder, FaTrash } from 'react-icons/fa';
|
||||
import { MdStar, MdStarBorder } from 'react-icons/md';
|
||||
import {
|
||||
useBulkDownloadImagesMutation,
|
||||
useStarImagesMutation,
|
||||
useUnstarImagesMutation,
|
||||
} from '../../../../services/api/endpoints/images';
|
||||
import { useFeatureStatus } from '../../../system/hooks/useFeatureStatus';
|
||||
import { addToast } from '../../../system/store/systemSlice';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const MultipleSelectionMenuItems = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const selection = useAppSelector((state) => state.gallery.selection);
|
||||
const customStarUi = useStore($customStarUI);
|
||||
|
||||
const isBulkDownloadEnabled =
|
||||
useFeatureStatus('bulkDownload').isFeatureEnabled;
|
||||
|
||||
const [starImages] = useStarImagesMutation();
|
||||
const [unstarImages] = useUnstarImagesMutation();
|
||||
const [bulkDownload] = useBulkDownloadImagesMutation();
|
||||
|
||||
const handleChangeBoard = useCallback(() => {
|
||||
dispatch(imagesToChangeSelected(selection));
|
||||
@ -40,6 +49,29 @@ const MultipleSelectionMenuItems = () => {
|
||||
unstarImages({ imageDTOs: selection });
|
||||
}, [unstarImages, selection]);
|
||||
|
||||
const handleBulkDownload = useCallback(async () => {
|
||||
try {
|
||||
const response = await bulkDownload({
|
||||
image_names: selection.map((img) => img.image_name),
|
||||
}).unwrap();
|
||||
|
||||
dispatch(
|
||||
addToast({
|
||||
title: t('gallery.preparingDownload'),
|
||||
status: 'success',
|
||||
...(response.response ? { description: response.response } : {}),
|
||||
})
|
||||
);
|
||||
} catch {
|
||||
dispatch(
|
||||
addToast({
|
||||
title: t('gallery.preparingDownloadFailed'),
|
||||
status: 'error',
|
||||
})
|
||||
);
|
||||
}
|
||||
}, [t, selection, bulkDownload, dispatch]);
|
||||
|
||||
const areAllStarred = useMemo(() => {
|
||||
return selection.every((img) => img.starred);
|
||||
}, [selection]);
|
||||
@ -66,6 +98,11 @@ const MultipleSelectionMenuItems = () => {
|
||||
{customStarUi ? customStarUi.on.text : `Star All`}
|
||||
</MenuItem>
|
||||
)}
|
||||
{isBulkDownloadEnabled && (
|
||||
<MenuItem icon={<FaDownload />} onClickCapture={handleBulkDownload}>
|
||||
{t('gallery.downloadSelection')}
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem icon={<FaFolder />} onClickCapture={handleChangeBoard}>
|
||||
Change Board
|
||||
</MenuItem>
|
||||
|
@ -7,7 +7,7 @@ export const initialConfigState: AppConfig = {
|
||||
shouldUpdateImagesOnConnect: false,
|
||||
shouldFetchMetadataFromApi: false,
|
||||
disabledTabs: [],
|
||||
disabledFeatures: ['lightbox', 'faceRestore', 'batches'],
|
||||
disabledFeatures: ['lightbox', 'faceRestore', 'batches', 'bulkDownload'],
|
||||
disabledSDFeatures: [
|
||||
'variation',
|
||||
'symmetry',
|
||||
|
@ -1599,6 +1599,19 @@ export const imagesApi = api.injectEndpoints({
|
||||
}
|
||||
},
|
||||
}),
|
||||
bulkDownloadImages: build.mutation<
|
||||
components['schemas']['ImagesDownloaded'],
|
||||
components['schemas']['Body_download_images_from_list']
|
||||
>({
|
||||
query: ({ image_names, board_id }) => ({
|
||||
url: `images/download`,
|
||||
method: 'POST',
|
||||
body: {
|
||||
image_names,
|
||||
board_id,
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
@ -1623,4 +1636,5 @@ export const {
|
||||
useStarImagesMutation,
|
||||
useUnstarImagesMutation,
|
||||
useGetImageMetadataFromFileQuery,
|
||||
useBulkDownloadImagesMutation,
|
||||
} = imagesApi;
|
||||
|
103
invokeai/frontend/web/src/services/api/schema.d.ts
vendored
103
invokeai/frontend/web/src/services/api/schema.d.ts
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user