feat(ui): add ability to archive/unarchive boards, add toggle to gallery settings to show/hide archived boards in list

This commit is contained in:
Mary Hipp 2024-06-26 14:04:10 -04:00 committed by psychedelicious
parent 5120a76ce5
commit 68c0aa898f
16 changed files with 404 additions and 170 deletions

View File

@ -17,6 +17,8 @@
}, },
"boards": { "boards": {
"addBoard": "Add Board", "addBoard": "Add Board",
"archiveBoard": "Archive Board",
"archived": "Archived",
"autoAddBoard": "Auto-Add Board", "autoAddBoard": "Auto-Add Board",
"bottomMessage": "Deleting this board and its images will reset any features currently using them.", "bottomMessage": "Deleting this board and its images will reset any features currently using them.",
"cancel": "Cancel", "cancel": "Cancel",
@ -36,6 +38,7 @@
"searchBoard": "Search Boards...", "searchBoard": "Search Boards...",
"selectBoard": "Select a Board", "selectBoard": "Select a Board",
"topMessage": "This board contains images used in the following features:", "topMessage": "This board contains images used in the following features:",
"unarchiveBoard": "Unarchive Board",
"uncategorized": "Uncategorized", "uncategorized": "Uncategorized",
"downloadBoard": "Download Board", "downloadBoard": "Download Board",
"imagesWithCount_one": "{{count}} image", "imagesWithCount_one": "{{count}} image",
@ -387,6 +390,7 @@
"openInViewer": "Open in Viewer", "openInViewer": "Open in Viewer",
"selectAllOnPage": "Select All On Page", "selectAllOnPage": "Select All On Page",
"selectAllOnBoard": "Select All On Board", "selectAllOnBoard": "Select All On Board",
"showArchivedBoards": "Show Archived Boards",
"selectForCompare": "Select for Compare", "selectForCompare": "Select for Compare",
"selectAnImageToCompare": "Select an Image to Compare", "selectAnImageToCompare": "Select an Image to Compare",
"slider": "Slider", "slider": "Slider",

View File

@ -11,6 +11,7 @@ import { memo, useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useListAllBoardsQuery } from 'services/api/endpoints/boards'; import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
import { useAddImagesToBoardMutation, useRemoveImagesFromBoardMutation } from 'services/api/endpoints/images'; import { useAddImagesToBoardMutation, useRemoveImagesFromBoardMutation } from 'services/api/endpoints/images';
import { selectListBoardsQueryArgs } from '../../gallery/store/gallerySelectors';
const selectImagesToChange = createMemoizedSelector( const selectImagesToChange = createMemoizedSelector(
selectChangeBoardModalSlice, selectChangeBoardModalSlice,
@ -20,7 +21,8 @@ const selectImagesToChange = createMemoizedSelector(
const ChangeBoardModal = () => { const ChangeBoardModal = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [selectedBoard, setSelectedBoard] = useState<string | null>(); const [selectedBoard, setSelectedBoard] = useState<string | null>();
const { data: boards, isFetching } = useListAllBoardsQuery(); const queryArgs = useAppSelector(selectListBoardsQueryArgs);
const { data: boards, isFetching } = useListAllBoardsQuery(queryArgs);
const isModalOpen = useAppSelector((s) => s.changeBoardModal.isModalOpen); const isModalOpen = useAppSelector((s) => s.changeBoardModal.isModalOpen);
const imagesToChange = useAppSelector(selectImagesToChange); const imagesToChange = useAppSelector(selectImagesToChange);
const [addImagesToBoard] = useAddImagesToBoardMutation(); const [addImagesToBoard] = useAddImagesToBoardMutation();

View File

@ -11,25 +11,28 @@ const BoardAutoAddSelect = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const autoAddBoardId = useAppSelector((s) => s.gallery.autoAddBoardId); const autoAddBoardId = useAppSelector((s) => s.gallery.autoAddBoardId);
const autoAssignBoardOnClick = useAppSelector((s) => s.gallery.autoAssignBoardOnClick); const autoAssignBoardOnClick = useAppSelector((s) => s.gallery.autoAssignBoardOnClick);
const { options, hasBoards } = useListAllBoardsQuery(undefined, { const { options, hasBoards } = useListAllBoardsQuery(
selectFromResult: ({ data }) => { {},
const options: ComboboxOption[] = [ {
{ selectFromResult: ({ data }) => {
label: t('controlnet.none'), const options: ComboboxOption[] = [
value: 'none', {
}, label: t('controlnet.none'),
].concat( value: 'none',
(data ?? []).map(({ board_id, board_name }) => ({ },
label: board_name, ].concat(
value: board_id, (data ?? []).map(({ board_id, board_name }) => ({
})) label: board_name,
); value: board_id,
return { }))
options, );
hasBoards: options.length > 1, return {
}; options,
}, hasBoards: options.length > 1,
}); };
},
}
);
const onChange = useCallback<ComboboxOnChange>( const onChange = useCallback<ComboboxOnChange>(
(v) => { (v) => {

View File

@ -7,12 +7,14 @@ import type { BoardId } from 'features/gallery/store/types';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { PiDownloadBold, PiPlusBold } from 'react-icons/pi'; import { PiArchiveBold, PiArchiveFill, PiDownloadBold, PiPlusBold } from 'react-icons/pi';
import { useBulkDownloadImagesMutation } from 'services/api/endpoints/images'; import { useBulkDownloadImagesMutation } from 'services/api/endpoints/images';
import { useBoardName } from 'services/api/hooks/useBoardName'; import { useBoardName } from 'services/api/hooks/useBoardName';
import type { BoardDTO } from 'services/api/types'; import type { BoardDTO } from 'services/api/types';
import GalleryBoardContextMenuItems from './GalleryBoardContextMenuItems'; import GalleryBoardContextMenuItems from './GalleryBoardContextMenuItems';
import { useUpdateBoardMutation } from '../../../../services/api/endpoints/boards';
import { MdArchive, MdUnarchive } from 'react-icons/md';
type Props = { type Props = {
board?: BoardDTO; board?: BoardDTO;
@ -30,6 +32,8 @@ const BoardContextMenu = ({ board, board_id, setBoardToDelete, children }: Props
[board] [board]
); );
const [updateBoard] = useUpdateBoardMutation();
const isSelectedForAutoAdd = useAppSelector(selectIsSelectedForAutoAdd); const isSelectedForAutoAdd = useAppSelector(selectIsSelectedForAutoAdd);
const boardName = useBoardName(board_id); const boardName = useBoardName(board_id);
const isBulkDownloadEnabled = useFeatureStatus('bulkDownload'); const isBulkDownloadEnabled = useFeatureStatus('bulkDownload');
@ -44,13 +48,31 @@ const BoardContextMenu = ({ board, board_id, setBoardToDelete, children }: Props
bulkDownload({ image_names: [], board_id: board_id }); bulkDownload({ image_names: [], board_id: board_id });
}, [board_id, bulkDownload]); }, [board_id, bulkDownload]);
const handleArchive = useCallback(() => {
updateBoard({
board_id,
changes: { archived: true },
});
}, [board_id, updateBoard]);
const handleUnarchive = useCallback(() => {
updateBoard({
board_id,
changes: { archived: false },
});
}, [board_id, updateBoard]);
const isBoardArchived = useMemo(() => {
return !!board?.archived;
}, [board]);
const renderMenuFunc = useCallback( const renderMenuFunc = useCallback(
() => ( () => (
<MenuList visibility="visible"> <MenuList visibility="visible">
<MenuGroup title={boardName}> <MenuGroup title={boardName}>
<MenuItem <MenuItem
icon={<PiPlusBold />} icon={<PiPlusBold />}
isDisabled={isSelectedForAutoAdd || autoAssignBoardOnClick} isDisabled={isSelectedForAutoAdd || autoAssignBoardOnClick || isBoardArchived}
onClick={handleSetAutoAdd} onClick={handleSetAutoAdd}
> >
{t('boards.menuItemAutoAdd')} {t('boards.menuItemAutoAdd')}
@ -60,6 +82,17 @@ const BoardContextMenu = ({ board, board_id, setBoardToDelete, children }: Props
{t('boards.downloadBoard')} {t('boards.downloadBoard')}
</MenuItem> </MenuItem>
)} )}
{board &&
(isBoardArchived ? (
<MenuItem icon={<PiArchiveBold />} onClick={handleUnarchive}>
{t('boards.unarchiveBoard')}
</MenuItem>
) : (
<MenuItem icon={<PiArchiveFill />} onClick={handleArchive}>
{t('boards.archiveBoard')}
</MenuItem>
))}
{board && <GalleryBoardContextMenuItems board={board} setBoardToDelete={setBoardToDelete} />} {board && <GalleryBoardContextMenuItems board={board} setBoardToDelete={setBoardToDelete} />}
</MenuGroup> </MenuGroup>
</MenuList> </MenuList>

View File

@ -3,9 +3,10 @@ import { useGetBoardAssetsTotalQuery, useGetBoardImagesTotalQuery } from 'servic
type Props = { type Props = {
board_id: string; board_id: string;
isArchived: boolean;
}; };
export const BoardTotalsTooltip = ({ board_id }: Props) => { export const BoardTotalsTooltip = ({ board_id, isArchived }: Props) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { imagesTotal } = useGetBoardImagesTotalQuery(board_id, { const { imagesTotal } = useGetBoardImagesTotalQuery(board_id, {
selectFromResult: ({ data }) => { selectFromResult: ({ data }) => {
@ -17,5 +18,5 @@ export const BoardTotalsTooltip = ({ board_id }: Props) => {
return { assetsTotal: data?.total ?? 0 }; return { assetsTotal: data?.total ?? 0 };
}, },
}); });
return `${t('boards.imagesWithCount', { count: imagesTotal })}, ${t('boards.assetsWithCount', { count: assetsTotal })}`; return `${t('boards.imagesWithCount', { count: imagesTotal })}, ${t('boards.assetsWithCount', { count: assetsTotal })}${isArchived ? ` (${t('boards.archived')})` : ''}`;
}; };

View File

@ -12,6 +12,7 @@ import AddBoardButton from './AddBoardButton';
import BoardsSearch from './BoardsSearch'; import BoardsSearch from './BoardsSearch';
import GalleryBoard from './GalleryBoard'; import GalleryBoard from './GalleryBoard';
import NoBoardBoard from './NoBoardBoard'; import NoBoardBoard from './NoBoardBoard';
import { selectListBoardsQueryArgs } from '../../../store/gallerySelectors';
const overlayScrollbarsStyles: CSSProperties = { const overlayScrollbarsStyles: CSSProperties = {
height: '100%', height: '100%',
@ -26,7 +27,9 @@ const BoardsList = (props: Props) => {
const { isOpen } = props; const { isOpen } = props;
const selectedBoardId = useAppSelector((s) => s.gallery.selectedBoardId); const selectedBoardId = useAppSelector((s) => s.gallery.selectedBoardId);
const boardSearchText = useAppSelector((s) => s.gallery.boardSearchText); const boardSearchText = useAppSelector((s) => s.gallery.boardSearchText);
const { data: boards } = useListAllBoardsQuery(); const queryArgs = useAppSelector(selectListBoardsQueryArgs);
console.log({ queryArgs });
const { data: boards } = useListAllBoardsQuery(queryArgs);
const filteredBoards = boardSearchText const filteredBoards = boardSearchText
? boards?.filter((board) => board.board_name.toLowerCase().includes(boardSearchText.toLowerCase())) ? boards?.filter((board) => board.board_name.toLowerCase().includes(boardSearchText.toLowerCase()))
: boards; : boards;

View File

@ -12,7 +12,7 @@ import { BoardTotalsTooltip } from 'features/gallery/components/Boards/BoardsLis
import { autoAddBoardIdChanged, boardIdSelected, selectGallerySlice } from 'features/gallery/store/gallerySlice'; import { autoAddBoardIdChanged, boardIdSelected, selectGallerySlice } from 'features/gallery/store/gallerySlice';
import { memo, useCallback, useMemo, useState } from 'react'; import { memo, useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { PiImagesSquare } from 'react-icons/pi'; import { PiArchiveBold, PiImagesSquare } from 'react-icons/pi';
import { useUpdateBoardMutation } from 'services/api/endpoints/boards'; import { useUpdateBoardMutation } from 'services/api/endpoints/boards';
import { useGetImageDTOQuery } from 'services/api/endpoints/images'; import { useGetImageDTOQuery } from 'services/api/endpoints/images';
import type { BoardDTO } from 'services/api/types'; import type { BoardDTO } from 'services/api/types';
@ -33,6 +33,7 @@ interface GalleryBoardProps {
const GalleryBoard = ({ board, isSelected, setBoardToDelete }: GalleryBoardProps) => { const GalleryBoard = ({ board, isSelected, setBoardToDelete }: GalleryBoardProps) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { t } = useTranslation();
const autoAssignBoardOnClick = useAppSelector((s) => s.gallery.autoAssignBoardOnClick); const autoAssignBoardOnClick = useAppSelector((s) => s.gallery.autoAssignBoardOnClick);
const selectIsSelectedForAutoAdd = useMemo( const selectIsSelectedForAutoAdd = useMemo(
() => createSelector(selectGallerySlice, (gallery) => board.board_id === gallery.autoAddBoardId), () => createSelector(selectGallerySlice, (gallery) => board.board_id === gallery.autoAddBoardId),
@ -103,7 +104,7 @@ const GalleryBoard = ({ board, isSelected, setBoardToDelete }: GalleryBoardProps
const handleChange = useCallback((newBoardName: string) => { const handleChange = useCallback((newBoardName: string) => {
setLocalBoardName(newBoardName); setLocalBoardName(newBoardName);
}, []); }, []);
const { t } = useTranslation();
return ( return (
<Box w="full" h="full" userSelect="none"> <Box w="full" h="full" userSelect="none">
<Flex <Flex
@ -118,7 +119,10 @@ const GalleryBoard = ({ board, isSelected, setBoardToDelete }: GalleryBoardProps
> >
<BoardContextMenu board={board} board_id={board_id} setBoardToDelete={setBoardToDelete}> <BoardContextMenu board={board} board_id={board_id} setBoardToDelete={setBoardToDelete}>
{(ref) => ( {(ref) => (
<Tooltip label={<BoardTotalsTooltip board_id={board.board_id} />} openDelay={1000}> <Tooltip
label={<BoardTotalsTooltip board_id={board.board_id} isArchived={Boolean(board.archived)} />}
openDelay={1000}
>
<Flex <Flex
ref={ref} ref={ref}
onClick={handleSelectBoard} onClick={handleSelectBoard}
@ -131,6 +135,25 @@ const GalleryBoard = ({ board, isSelected, setBoardToDelete }: GalleryBoardProps
cursor="pointer" cursor="pointer"
bg="base.800" bg="base.800"
> >
{board.archived && (
<Box
sx={{
position: 'absolute',
top: 1,
insetInlineEnd: 2,
p: 0,
minW: 0,
svg: {
transitionProperty: 'common',
transitionDuration: 'normal',
fill: 'base.300',
filter: 'drop-shadow(0px 0px 0.1rem var(--invoke-colors-base-800))',
},
}}
>
<Icon as={PiArchiveBold} />
</Box>
)}
{coverImage?.thumbnail_url ? ( {coverImage?.thumbnail_url ? (
<Image <Image
src={coverImage?.thumbnail_url} src={coverImage?.thumbnail_url}

View File

@ -19,6 +19,7 @@ import {
autoAssignBoardOnClickChanged, autoAssignBoardOnClickChanged,
setGalleryImageMinimumWidth, setGalleryImageMinimumWidth,
shouldAutoSwitchChanged, shouldAutoSwitchChanged,
shouldShowArchivedBoardsChanged,
} from 'features/gallery/store/gallerySlice'; } from 'features/gallery/store/gallerySlice';
import type { ChangeEvent } from 'react'; import type { ChangeEvent } from 'react';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
@ -38,6 +39,7 @@ const GallerySettingsPopover = () => {
const shouldAutoSwitch = useAppSelector((s) => s.gallery.shouldAutoSwitch); const shouldAutoSwitch = useAppSelector((s) => s.gallery.shouldAutoSwitch);
const autoAssignBoardOnClick = useAppSelector((s) => s.gallery.autoAssignBoardOnClick); const autoAssignBoardOnClick = useAppSelector((s) => s.gallery.autoAssignBoardOnClick);
const alwaysShowImageSizeBadge = useAppSelector((s) => s.gallery.alwaysShowImageSizeBadge); const alwaysShowImageSizeBadge = useAppSelector((s) => s.gallery.alwaysShowImageSizeBadge);
const shouldShowArchivedBoards = useAppSelector((s) => s.gallery.shouldShowArchivedBoards);
const handleChangeGalleryImageMinimumWidth = useCallback( const handleChangeGalleryImageMinimumWidth = useCallback(
(v: number) => { (v: number) => {
@ -63,6 +65,11 @@ const GallerySettingsPopover = () => {
[dispatch] [dispatch]
); );
const handleChangeShouldShowArchivedBoardsChanged = useCallback(
(e: ChangeEvent<HTMLInputElement>) => dispatch(shouldShowArchivedBoardsChanged(e.target.checked)),
[dispatch]
);
return ( return (
<Popover isLazy> <Popover isLazy>
<PopoverTrigger> <PopoverTrigger>
@ -99,6 +106,10 @@ const GallerySettingsPopover = () => {
<FormLabel>{t('gallery.alwaysShowImageSizeBadge')}</FormLabel> <FormLabel>{t('gallery.alwaysShowImageSizeBadge')}</FormLabel>
<Checkbox isChecked={alwaysShowImageSizeBadge} onChange={handleChangeAlwaysShowImageSizeBadgeChanged} /> <Checkbox isChecked={alwaysShowImageSizeBadge} onChange={handleChangeAlwaysShowImageSizeBadgeChanged} />
</FormControl> </FormControl>
<FormControl>
<FormLabel>{t('gallery.showArchivedBoards')}</FormLabel>
<Checkbox isChecked={shouldShowArchivedBoards} onChange={handleChangeShouldShowArchivedBoardsChanged} />
</FormControl>
</FormControlGroup> </FormControlGroup>
<BoardAutoAddSelect /> <BoardAutoAddSelect />
</Flex> </Flex>

View File

@ -3,7 +3,7 @@ import { skipToken } from '@reduxjs/toolkit/query';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { selectGallerySlice } from 'features/gallery/store/gallerySlice'; import { selectGallerySlice } from 'features/gallery/store/gallerySlice';
import { ASSETS_CATEGORIES, IMAGE_CATEGORIES } from 'features/gallery/store/types'; import { ASSETS_CATEGORIES, IMAGE_CATEGORIES } from 'features/gallery/store/types';
import type { ListImagesArgs } from 'services/api/types'; import type { ListBoardsArgs, ListImagesArgs } from 'services/api/types';
export const selectLastSelectedImage = createMemoizedSelector( export const selectLastSelectedImage = createMemoizedSelector(
selectGallerySlice, selectGallerySlice,
@ -23,3 +23,10 @@ export const selectListImagesQueryArgs = createMemoizedSelector(
} }
: skipToken : skipToken
); );
export const selectListBoardsQueryArgs = createMemoizedSelector(
selectGallerySlice,
(gallery): ListBoardsArgs => ({
archived: gallery.shouldShowArchivedBoards ? true : undefined
})
);

View File

@ -25,6 +25,7 @@ const initialGalleryState: GalleryState = {
imageToCompare: null, imageToCompare: null,
comparisonMode: 'slider', comparisonMode: 'slider',
comparisonFit: 'fill', comparisonFit: 'fill',
shouldShowArchivedBoards: false,
}; };
export const gallerySlice = createSlice({ export const gallerySlice = createSlice({
@ -110,6 +111,9 @@ export const gallerySlice = createSlice({
limitChanged: (state, action: PayloadAction<number>) => { limitChanged: (state, action: PayloadAction<number>) => {
state.limit = action.payload; state.limit = action.payload;
}, },
shouldShowArchivedBoardsChanged: (state, action: PayloadAction<boolean>) => {
state.shouldShowArchivedBoards = action.payload;
},
}, },
extraReducers: (builder) => { extraReducers: (builder) => {
builder.addMatcher(isAnyBoardDeleted, (state, action) => { builder.addMatcher(isAnyBoardDeleted, (state, action) => {
@ -154,6 +158,7 @@ export const {
comparisonModeCycled, comparisonModeCycled,
offsetChanged, offsetChanged,
limitChanged, limitChanged,
shouldShowArchivedBoardsChanged,
} = gallerySlice.actions; } = gallerySlice.actions;
const isAnyBoardDeleted = isAnyOf( const isAnyBoardDeleted = isAnyOf(

View File

@ -25,4 +25,5 @@ export type GalleryState = {
comparisonMode: ComparisonMode; comparisonMode: ComparisonMode;
comparisonFit: ComparisonFit; comparisonFit: ComparisonFit;
isImageViewerOpen: boolean; isImageViewerOpen: boolean;
shouldShowArchivedBoards: boolean;
}; };

View File

@ -1,6 +1,6 @@
import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui-library'; import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui-library';
import { Combobox, FormControl } from '@invoke-ai/ui-library'; import { Combobox, FormControl } from '@invoke-ai/ui-library';
import { useAppDispatch } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { fieldBoardValueChanged } from 'features/nodes/store/nodesSlice'; import { fieldBoardValueChanged } from 'features/nodes/store/nodesSlice';
import type { BoardFieldInputInstance, BoardFieldInputTemplate } from 'features/nodes/types/field'; import type { BoardFieldInputInstance, BoardFieldInputTemplate } from 'features/nodes/types/field';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
@ -8,12 +8,14 @@ import { useTranslation } from 'react-i18next';
import { useListAllBoardsQuery } from 'services/api/endpoints/boards'; import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
import type { FieldComponentProps } from './types'; import type { FieldComponentProps } from './types';
import { selectListBoardsQueryArgs } from '../../../../../../../gallery/store/gallerySelectors';
const BoardFieldInputComponent = (props: FieldComponentProps<BoardFieldInputInstance, BoardFieldInputTemplate>) => { const BoardFieldInputComponent = (props: FieldComponentProps<BoardFieldInputInstance, BoardFieldInputTemplate>) => {
const { nodeId, field } = props; const { nodeId, field } = props;
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { t } = useTranslation(); const { t } = useTranslation();
const { options, hasBoards } = useListAllBoardsQuery(undefined, { const queryArgs = useAppSelector(selectListBoardsQueryArgs);
const { options, hasBoards } = useListAllBoardsQuery(queryArgs, {
selectFromResult: ({ data }) => { selectFromResult: ({ data }) => {
const options: ComboboxOption[] = [ const options: ComboboxOption[] = [
{ {

View File

@ -1,5 +1,5 @@
import { ASSETS_CATEGORIES, IMAGE_CATEGORIES } from 'features/gallery/store/types'; import { ASSETS_CATEGORIES, IMAGE_CATEGORIES } from 'features/gallery/store/types';
import type { BoardDTO, OffsetPaginatedResults_ImageDTO_, UpdateBoardArg } from 'services/api/types'; import type { BoardDTO, ListBoardsArgs, OffsetPaginatedResults_ImageDTO_, UpdateBoardArg } from 'services/api/types';
import { getListImagesUrl } from 'services/api/util'; import { getListImagesUrl } from 'services/api/util';
import type { ApiTagDescription } from '..'; import type { ApiTagDescription } from '..';
@ -18,10 +18,10 @@ export const boardsApi = api.injectEndpoints({
/** /**
* Boards Queries * Boards Queries
*/ */
listAllBoards: build.query<Array<BoardDTO>, void>({ listAllBoards: build.query<Array<BoardDTO>, ListBoardsArgs>({
query: () => ({ query: (args) => ({
url: buildBoardsUrl(), url: buildBoardsUrl(),
params: { all: true }, params: { all: true, ...args },
}), }),
providesTags: (result) => { providesTags: (result) => {
// any list of boards // any list of boards

View File

@ -1,9 +1,10 @@
import type { BoardId } from 'features/gallery/store/types'; import type { BoardId } from 'features/gallery/store/types';
import { t } from 'i18next'; import { t } from 'i18next';
import { useListAllBoardsQuery } from 'services/api/endpoints/boards'; import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
import { selectListBoardsQueryArgs } from '../../../features/gallery/store/gallerySelectors';
export const useBoardName = (board_id: BoardId) => { export const useBoardName = (board_id: BoardId) => {
const { boardName } = useListAllBoardsQuery(undefined, { const { boardName } = useListAllBoardsQuery({}, {
selectFromResult: ({ data }) => { selectFromResult: ({ data }) => {
const selectedBoard = data?.find((b) => b.board_id === board_id); const selectedBoard = data?.find((b) => b.board_id === board_id);
const boardName = selectedBoard?.board_name || t('boards.uncategorized'); const boardName = selectedBoard?.board_name || t('boards.uncategorized');

File diff suppressed because one or more lines are too long

View File

@ -6,6 +6,8 @@ export type S = components['schemas'];
export type ListImagesArgs = NonNullable<paths['/api/v1/images/']['get']['parameters']['query']>; export type ListImagesArgs = NonNullable<paths['/api/v1/images/']['get']['parameters']['query']>;
export type ListImagesResponse = paths['/api/v1/images/']['get']['responses']['200']['content']['application/json']; export type ListImagesResponse = paths['/api/v1/images/']['get']['responses']['200']['content']['application/json'];
export type ListBoardsArgs = NonNullable<paths['/api/v1/boards/']['get']['parameters']['query']>;
export type DeleteBoardResult = export type DeleteBoardResult =
paths['/api/v1/boards/{board_id}']['delete']['responses']['200']['content']['application/json']; paths['/api/v1/boards/{board_id}']['delete']['responses']['200']['content']['application/json'];