From 5709f82e5f293c7258cf7117d28a50359810e8a0 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 27 Jun 2024 14:36:01 +1000 Subject: [PATCH] feat(ui): separate context menu for no board board Much easier to not need to handle the board being optional in the component. --- .../components/Boards/BoardContextMenu.tsx | 65 +++++++++---------- .../Boards/BoardsList/GalleryBoard.tsx | 2 +- .../Boards/BoardsList/NoBoardBoard.tsx | 8 +-- .../Boards/NoBoardBoardContextMenu.tsx | 57 ++++++++++++++++ 4 files changed, 91 insertions(+), 41 deletions(-) create mode 100644 invokeai/frontend/web/src/features/gallery/components/Boards/NoBoardBoardContextMenu.tsx diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardContextMenu.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardContextMenu.tsx index d3c5121567..3be9fef1f8 100644 --- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardContextMenu.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardContextMenu.tsx @@ -1,9 +1,8 @@ import type { ContextMenuProps } from '@invoke-ai/ui-library'; -import { ContextMenu, MenuGroup, MenuItem, MenuList, Tooltip } from '@invoke-ai/ui-library'; +import { ContextMenu, MenuGroup, MenuItem, MenuList } from '@invoke-ai/ui-library'; import { createSelector } from '@reduxjs/toolkit'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { autoAddBoardIdChanged, selectGallerySlice } from 'features/gallery/store/gallerySlice'; -import type { BoardId } from 'features/gallery/store/types'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { memo, useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -16,54 +15,49 @@ import type { BoardDTO } from 'services/api/types'; import GalleryBoardContextMenuItems from './GalleryBoardContextMenuItems'; type Props = { - board?: BoardDTO; - board_id: BoardId; + board: BoardDTO; children: ContextMenuProps['children']; - setBoardToDelete?: (board?: BoardDTO) => void; + setBoardToDelete: (board?: BoardDTO) => void; }; -const BoardContextMenu = ({ board, board_id, setBoardToDelete, children }: Props) => { +const BoardContextMenu = ({ board, setBoardToDelete, children }: Props) => { const { t } = useTranslation(); const dispatch = useAppDispatch(); const autoAssignBoardOnClick = useAppSelector((s) => s.gallery.autoAssignBoardOnClick); const selectIsSelectedForAutoAdd = useMemo( - () => createSelector(selectGallerySlice, (gallery) => board && board.board_id === gallery.autoAddBoardId), - [board] + () => createSelector(selectGallerySlice, (gallery) => board.board_id === gallery.autoAddBoardId), + [board.board_id] ); const [updateBoard] = useUpdateBoardMutation(); const isSelectedForAutoAdd = useAppSelector(selectIsSelectedForAutoAdd); - const boardName = useBoardName(board_id); + const boardName = useBoardName(board.board_id); const isBulkDownloadEnabled = useFeatureStatus('bulkDownload'); const [bulkDownload] = useBulkDownloadImagesMutation(); const handleSetAutoAdd = useCallback(() => { - dispatch(autoAddBoardIdChanged(board_id)); - }, [board_id, dispatch]); + dispatch(autoAddBoardIdChanged(board.board_id)); + }, [board.board_id, dispatch]); const handleBulkDownload = useCallback(() => { - bulkDownload({ image_names: [], board_id: board_id }); - }, [board_id, bulkDownload]); + bulkDownload({ image_names: [], board_id: board.board_id }); + }, [board.board_id, bulkDownload]); const handleArchive = useCallback(() => { updateBoard({ - board_id, + board_id: board.board_id, changes: { archived: true }, }); - }, [board_id, updateBoard]); + }, [board.board_id, updateBoard]); const handleUnarchive = useCallback(() => { updateBoard({ - board_id, + board_id: board.board_id, changes: { archived: false }, }); - }, [board_id, updateBoard]); - - const isBoardArchived = useMemo(() => { - return !!board?.archived; - }, [board]); + }, [board.board_id, updateBoard]); const renderMenuFunc = useCallback( () => ( @@ -71,7 +65,7 @@ const BoardContextMenu = ({ board, board_id, setBoardToDelete, children }: Props } - isDisabled={isSelectedForAutoAdd || autoAssignBoardOnClick || isBoardArchived} + isDisabled={isSelectedForAutoAdd || autoAssignBoardOnClick || Boolean(board?.archived)} onClick={handleSetAutoAdd} > {t('boards.menuItemAutoAdd')} @@ -81,20 +75,20 @@ const BoardContextMenu = ({ board, board_id, setBoardToDelete, children }: Props {t('boards.downloadBoard')} )} - {board && - (isBoardArchived ? ( - } onClick={handleUnarchive}> - {t('boards.unarchiveBoard')} - - ) : ( - - } onClick={handleArchive} isDisabled={isSelectedForAutoAdd}> - {t('boards.archiveBoard')} - - - ))} - {board && } + {board.archived && ( + } onClick={handleUnarchive}> + {t('boards.unarchiveBoard')} + + )} + + {!board.archived && ( + } onClick={handleArchive} isDisabled={isSelectedForAutoAdd}> + {t('boards.archiveBoard')} + + )} + + ), @@ -110,7 +104,6 @@ const BoardContextMenu = ({ board, board_id, setBoardToDelete, children }: Props t, handleArchive, handleUnarchive, - isBoardArchived, ] ); diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/GalleryBoard.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/GalleryBoard.tsx index 235105d21d..fa5ed15930 100644 --- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/GalleryBoard.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/GalleryBoard.tsx @@ -125,7 +125,7 @@ const GalleryBoard = ({ board, isSelected, setBoardToDelete }: GalleryBoardProps w="full" h="full" > - + {(ref) => ( } diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/NoBoardBoard.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/NoBoardBoard.tsx index 3904dc7c98..2e823ea25b 100644 --- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/NoBoardBoard.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/NoBoardBoard.tsx @@ -4,8 +4,8 @@ import IAIDroppable from 'common/components/IAIDroppable'; import SelectionOverlay from 'common/components/SelectionOverlay'; import type { RemoveFromBoardDropData } from 'features/dnd/types'; import AutoAddIcon from 'features/gallery/components/Boards/AutoAddIcon'; -import BoardContextMenu from 'features/gallery/components/Boards/BoardContextMenu'; import { BoardTotalsTooltip } from 'features/gallery/components/Boards/BoardsList/BoardTotalsTooltip'; +import NoBoardBoardContextMenu from 'features/gallery/components/Boards/NoBoardBoardContextMenu'; import { autoAddBoardIdChanged, boardIdSelected } from 'features/gallery/store/gallerySlice'; import InvokeLogoSVG from 'public/assets/images/invoke-symbol-wht-lrg.svg'; import { memo, useCallback, useMemo, useState } from 'react'; @@ -58,9 +58,9 @@ const NoBoardBoard = memo(({ isSelected }: Props) => { w="full" h="full" > - + {(ref) => ( - } openDelay={1000}> + } openDelay={1000}> { )} - + ); diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/NoBoardBoardContextMenu.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/NoBoardBoardContextMenu.tsx new file mode 100644 index 0000000000..b15226b9e6 --- /dev/null +++ b/invokeai/frontend/web/src/features/gallery/components/Boards/NoBoardBoardContextMenu.tsx @@ -0,0 +1,57 @@ +import type { ContextMenuProps } from '@invoke-ai/ui-library'; +import { ContextMenu, MenuGroup, MenuItem, MenuList } from '@invoke-ai/ui-library'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { autoAddBoardIdChanged } from 'features/gallery/store/gallerySlice'; +import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; +import { memo, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; +import { PiDownloadBold, PiPlusBold } from 'react-icons/pi'; +import { useBulkDownloadImagesMutation } from 'services/api/endpoints/images'; + +type Props = { + children: ContextMenuProps['children']; +}; + +const NoBoardBoardContextMenu = ({ children }: Props) => { + const { t } = useTranslation(); + const dispatch = useAppDispatch(); + const autoAssignBoardOnClick = useAppSelector((s) => s.gallery.autoAssignBoardOnClick); + const isSelectedForAutoAdd = useAppSelector((s) => s.gallery.autoAddBoardId === 'none'); + const isBulkDownloadEnabled = useFeatureStatus('bulkDownload'); + + const [bulkDownload] = useBulkDownloadImagesMutation(); + + const handleSetAutoAdd = useCallback(() => { + dispatch(autoAddBoardIdChanged('none')); + }, [dispatch]); + + const handleBulkDownload = useCallback(() => { + bulkDownload({ image_names: [], board_id: 'none' }); + }, [bulkDownload]); + + const renderMenuFunc = useCallback( + () => ( + + + } + isDisabled={isSelectedForAutoAdd || autoAssignBoardOnClick} + onClick={handleSetAutoAdd} + > + {t('boards.menuItemAutoAdd')} + + {isBulkDownloadEnabled && ( + } onClickCapture={handleBulkDownload}> + {t('boards.downloadBoard')} + + )} + + + ), + [autoAssignBoardOnClick, handleBulkDownload, handleSetAutoAdd, isBulkDownloadEnabled, isSelectedForAutoAdd, t] + ); + + return {children}; +}; + +export default memo(NoBoardBoardContextMenu);