mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
can delete and rename boards
This commit is contained in:
parent
d306a84447
commit
8aac683319
@ -1,9 +1,19 @@
|
|||||||
import { Flex, Icon, Text } from '@chakra-ui/react';
|
import { Flex, Icon, Text } from '@chakra-ui/react';
|
||||||
|
import { useCallback } from 'react';
|
||||||
import { FaPlus } from 'react-icons/fa';
|
import { FaPlus } from 'react-icons/fa';
|
||||||
|
import { useAppDispatch } from '../../../../app/store/storeHooks';
|
||||||
|
import { boardCreated } from '../../../../services/thunks/board';
|
||||||
|
|
||||||
const AddBoardButton = () => {
|
const AddBoardButton = () => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
const handleCreateBoard = useCallback(() => {
|
||||||
|
dispatch(boardCreated({ requestBody: 'My Board' }));
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
|
onClick={handleCreateBoard}
|
||||||
sx={{
|
sx={{
|
||||||
flexDir: 'column',
|
flexDir: 'column',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
import { Flex, Icon, Text } from '@chakra-ui/react';
|
||||||
|
import { FaImages } from 'react-icons/fa';
|
||||||
|
import { boardIdSelected } from '../../store/boardSlice';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
|
const AllImagesBoard = ({ isSelected }: { isSelected: boolean }) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const handleAllImagesBoardClick = () => {
|
||||||
|
dispatch(boardIdSelected(null));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
flexDir: 'column',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
cursor: 'pointer',
|
||||||
|
w: 'full',
|
||||||
|
h: 'full',
|
||||||
|
gap: 1,
|
||||||
|
}}
|
||||||
|
onClick={handleAllImagesBoardClick}
|
||||||
|
>
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
borderWidth: '1px',
|
||||||
|
borderRadius: 'base',
|
||||||
|
borderColor: isSelected ? 'base.500' : 'base.800',
|
||||||
|
w: 'full',
|
||||||
|
h: 'full',
|
||||||
|
aspectRatio: '1/1',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon boxSize={8} color="base.700" as={FaImages} />
|
||||||
|
</Flex>
|
||||||
|
<Text sx={{ color: 'base.200', fontSize: 'xs' }}>All Images</Text>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AllImagesBoard;
|
@ -2,22 +2,26 @@ import { Grid } from '@chakra-ui/react';
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import { selectBoardsAll } from 'features/gallery/store/boardSlice';
|
import {
|
||||||
import { memo } from 'react';
|
boardsSelector,
|
||||||
|
selectBoardsAll,
|
||||||
|
} from 'features/gallery/store/boardSlice';
|
||||||
|
import { memo, useState } from 'react';
|
||||||
import HoverableBoard from './HoverableBoard';
|
import HoverableBoard from './HoverableBoard';
|
||||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||||
import AddBoardButton from './AddBoardButton';
|
import AddBoardButton from './AddBoardButton';
|
||||||
|
import AllImagesBoard from './AllImagesBoard';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
selectBoardsAll,
|
[selectBoardsAll, boardsSelector],
|
||||||
(boards) => {
|
(boards, boardsState) => {
|
||||||
return { boards };
|
return { boards, selectedBoardId: boardsState.selectedBoardId };
|
||||||
},
|
},
|
||||||
defaultSelectorOptions
|
defaultSelectorOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
const BoardsList = () => {
|
const BoardsList = () => {
|
||||||
const { boards } = useAppSelector(selector);
|
const { boards, selectedBoardId } = useAppSelector(selector);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OverlayScrollbarsComponent
|
<OverlayScrollbarsComponent
|
||||||
@ -42,8 +46,13 @@ const BoardsList = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AddBoardButton />
|
<AddBoardButton />
|
||||||
|
<AllImagesBoard isSelected={selectedBoardId === null} />
|
||||||
{boards.map((board) => (
|
{boards.map((board) => (
|
||||||
<HoverableBoard key={board.board_id} board={board} />
|
<HoverableBoard
|
||||||
|
key={board.board_id}
|
||||||
|
board={board}
|
||||||
|
isSelected={selectedBoardId === board.board_id}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
</OverlayScrollbarsComponent>
|
</OverlayScrollbarsComponent>
|
||||||
|
@ -1,49 +1,51 @@
|
|||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
|
Editable,
|
||||||
|
EditableInput,
|
||||||
|
EditablePreview,
|
||||||
Flex,
|
Flex,
|
||||||
Icon,
|
Icon,
|
||||||
Image,
|
Image,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
MenuList,
|
MenuList,
|
||||||
Text,
|
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
import { PropsWithChildren, memo, useCallback, useState } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { FaFolder, FaImage } from 'react-icons/fa';
|
import { FaFolder, FaTrash } from 'react-icons/fa';
|
||||||
import { ContextMenu } from 'chakra-ui-contextmenu';
|
import { ContextMenu } from 'chakra-ui-contextmenu';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { ExternalLinkIcon } from '@chakra-ui/icons';
|
|
||||||
import { useAppToaster } from 'app/components/Toaster';
|
|
||||||
import { BoardDTO } from 'services/api';
|
import { BoardDTO } from 'services/api';
|
||||||
import { EntityId, createSelector } from '@reduxjs/toolkit';
|
|
||||||
import {
|
|
||||||
selectFilteredImagesIds,
|
|
||||||
selectImagesById,
|
|
||||||
} from '../../store/imagesSlice';
|
|
||||||
import { RootState } from '../../../../app/store/store';
|
|
||||||
import { defaultSelectorOptions } from '../../../../app/store/util/defaultMemoizeOptions';
|
|
||||||
import { useSelector } from 'react-redux';
|
|
||||||
import { IAIImageFallback } from 'common/components/IAIImageFallback';
|
import { IAIImageFallback } from 'common/components/IAIImageFallback';
|
||||||
import { boardIdSelected } from 'features/gallery/store/boardSlice';
|
import { boardIdSelected } from 'features/gallery/store/boardSlice';
|
||||||
|
import { boardDeleted, boardUpdated } from '../../../../services/thunks/board';
|
||||||
|
|
||||||
interface HoverableBoardProps {
|
interface HoverableBoardProps {
|
||||||
board: BoardDTO;
|
board: BoardDTO;
|
||||||
|
isSelected: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
const HoverableBoard = memo(({ board, isSelected }: HoverableBoardProps) => {
|
||||||
* Gallery image component with delete/use all/use seed buttons on hover.
|
|
||||||
*/
|
|
||||||
const HoverableBoard = memo(({ board }: HoverableBoardProps) => {
|
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const { board_name, board_id, cover_image_url } = board;
|
const { board_name, board_id, cover_image_url } = board;
|
||||||
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const handleSelectBoard = useCallback(() => {
|
const handleSelectBoard = useCallback(() => {
|
||||||
dispatch(boardIdSelected(board_id));
|
dispatch(boardIdSelected(board_id));
|
||||||
}, [board_id, dispatch]);
|
}, [board_id, dispatch]);
|
||||||
|
|
||||||
|
const handleDeleteBoard = useCallback(() => {
|
||||||
|
dispatch(boardDeleted(board_id));
|
||||||
|
}, [board_id, dispatch]);
|
||||||
|
|
||||||
|
const handleUpdateBoardName = (newBoardName: string) => {
|
||||||
|
dispatch(
|
||||||
|
boardUpdated({
|
||||||
|
boardId: board_id,
|
||||||
|
requestBody: { board_name: newBoardName },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ touchAction: 'none' }}>
|
<Box sx={{ touchAction: 'none' }}>
|
||||||
<ContextMenu<HTMLDivElement>
|
<ContextMenu<HTMLDivElement>
|
||||||
@ -51,10 +53,11 @@ const HoverableBoard = memo(({ board }: HoverableBoardProps) => {
|
|||||||
renderMenu={() => (
|
renderMenu={() => (
|
||||||
<MenuList sx={{ visibility: 'visible !important' }}>
|
<MenuList sx={{ visibility: 'visible !important' }}>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon={<ExternalLinkIcon />}
|
sx={{ color: 'error.300' }}
|
||||||
// onClickCapture={handleOpenInNewTab}
|
icon={<FaTrash />}
|
||||||
|
onClickCapture={handleDeleteBoard}
|
||||||
>
|
>
|
||||||
Sample Menu Item
|
Delete Board
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</MenuList>
|
</MenuList>
|
||||||
)}
|
)}
|
||||||
@ -64,7 +67,6 @@ const HoverableBoard = memo(({ board }: HoverableBoardProps) => {
|
|||||||
position="relative"
|
position="relative"
|
||||||
key={board_id}
|
key={board_id}
|
||||||
userSelect="none"
|
userSelect="none"
|
||||||
onClick={handleSelectBoard}
|
|
||||||
ref={ref}
|
ref={ref}
|
||||||
sx={{
|
sx={{
|
||||||
flexDir: 'column',
|
flexDir: 'column',
|
||||||
@ -77,12 +79,13 @@ const HoverableBoard = memo(({ board }: HoverableBoardProps) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Flex
|
<Flex
|
||||||
|
onClick={handleSelectBoard}
|
||||||
sx={{
|
sx={{
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
borderWidth: '1px',
|
borderWidth: '1px',
|
||||||
borderRadius: 'base',
|
borderRadius: 'base',
|
||||||
borderColor: 'base.800',
|
borderColor: isSelected ? 'base.500' : 'base.800',
|
||||||
w: 'full',
|
w: 'full',
|
||||||
h: 'full',
|
h: 'full',
|
||||||
aspectRatio: '1/1',
|
aspectRatio: '1/1',
|
||||||
@ -102,7 +105,26 @@ const HoverableBoard = memo(({ board }: HoverableBoardProps) => {
|
|||||||
<Icon boxSize={8} color="base.700" as={FaFolder} />
|
<Icon boxSize={8} color="base.700" as={FaFolder} />
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
<Text sx={{ color: 'base.200', fontSize: 'xs' }}>{board_name}</Text>
|
|
||||||
|
<Editable
|
||||||
|
defaultValue={board_name}
|
||||||
|
submitOnBlur={false}
|
||||||
|
onSubmit={(nextValue) => {
|
||||||
|
handleUpdateBoardName(nextValue);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<EditablePreview
|
||||||
|
sx={{ color: 'base.200', fontSize: 'xs', textAlign: 'left' }}
|
||||||
|
/>
|
||||||
|
<EditableInput
|
||||||
|
sx={{
|
||||||
|
color: 'base.200',
|
||||||
|
fontSize: 'xs',
|
||||||
|
textAlign: 'left',
|
||||||
|
borderColor: 'base.500',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Editable>
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
|
@ -37,7 +37,7 @@ import {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { BsPinAngle, BsPinAngleFill } from 'react-icons/bs';
|
import { BsPinAngle, BsPinAngleFill } from 'react-icons/bs';
|
||||||
import { FaFolder, FaImage, FaPlus, FaServer, FaWrench } from 'react-icons/fa';
|
import { FaImage, FaServer, FaWrench } from 'react-icons/fa';
|
||||||
import { MdPhotoLibrary } from 'react-icons/md';
|
import { MdPhotoLibrary } from 'react-icons/md';
|
||||||
import HoverableImage from './HoverableImage';
|
import HoverableImage from './HoverableImage';
|
||||||
|
|
||||||
@ -55,10 +55,6 @@ import {
|
|||||||
} from '../store/imagesSlice';
|
} from '../store/imagesSlice';
|
||||||
import { receivedPageOfImages } from 'services/thunks/image';
|
import { receivedPageOfImages } from 'services/thunks/image';
|
||||||
import { boardSelector } from '../store/boardSelectors';
|
import { boardSelector } from '../store/boardSelectors';
|
||||||
import { BoardDTO, ImageDTO } from '../../../services/api';
|
|
||||||
import { isBoardDTO, isImageDTO } from '../../../services/types/guards';
|
|
||||||
import HoverableBoard from './Boards/HoverableBoard';
|
|
||||||
import IAIInput from '../../../common/components/IAIInput';
|
|
||||||
import { boardCreated } from '../../../services/thunks/board';
|
import { boardCreated } from '../../../services/thunks/board';
|
||||||
import BoardsList from './Boards/BoardsList';
|
import BoardsList from './Boards/BoardsList';
|
||||||
import { selectBoardsById } from '../store/boardSlice';
|
import { selectBoardsById } from '../store/boardSlice';
|
||||||
@ -66,18 +62,16 @@ import { selectBoardsById } from '../store/boardSlice';
|
|||||||
const itemSelector = createSelector(
|
const itemSelector = createSelector(
|
||||||
[(state: RootState) => state],
|
[(state: RootState) => state],
|
||||||
(state) => {
|
(state) => {
|
||||||
const { images, boards, gallery } = state;
|
const { images, boards } = state;
|
||||||
|
|
||||||
let items: Array<ImageDTO | BoardDTO> = [];
|
|
||||||
let areMoreAvailable = false;
|
|
||||||
let isLoading = true;
|
|
||||||
|
|
||||||
const { categories } = images;
|
const { categories } = images;
|
||||||
|
|
||||||
const allImages = selectImagesAll(state);
|
const allImages = selectImagesAll(state);
|
||||||
items = allImages.filter((i) => categories.includes(i.image_category));
|
const items = allImages.filter((i) =>
|
||||||
areMoreAvailable = items.length < images.total;
|
categories.includes(i.image_category)
|
||||||
isLoading = images.isLoading;
|
);
|
||||||
|
const areMoreAvailable = items.length < images.total;
|
||||||
|
const isLoading = images.isLoading;
|
||||||
|
|
||||||
const selectedBoard = boards.selectedBoardId
|
const selectedBoard = boards.selectedBoardId
|
||||||
? selectBoardsById(state, boards.selectedBoardId)
|
? selectBoardsById(state, boards.selectedBoardId)
|
||||||
@ -353,9 +347,7 @@ const ImageGalleryContent = () => {
|
|||||||
data={items}
|
data={items}
|
||||||
endReached={handleEndReached}
|
endReached={handleEndReached}
|
||||||
scrollerRef={(ref) => setScrollerRef(ref)}
|
scrollerRef={(ref) => setScrollerRef(ref)}
|
||||||
itemContent={(index, item) => {
|
itemContent={(index, item) => (
|
||||||
if (isImageDTO(item)) {
|
|
||||||
return (
|
|
||||||
<Flex sx={{ pb: 2 }}>
|
<Flex sx={{ pb: 2 }}>
|
||||||
<HoverableImage
|
<HoverableImage
|
||||||
key={`${item.image_name}-${item.thumbnail_url}`}
|
key={`${item.image_name}-${item.thumbnail_url}`}
|
||||||
@ -365,15 +357,7 @@ const ImageGalleryContent = () => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
)}
|
||||||
} else if (isBoardDTO(item)) {
|
|
||||||
return (
|
|
||||||
<Flex sx={{ pb: 2 }}>
|
|
||||||
<HoverableBoard key={item.board_id} board={item} />
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<VirtuosoGrid
|
<VirtuosoGrid
|
||||||
@ -385,9 +369,7 @@ const ImageGalleryContent = () => {
|
|||||||
List: ListContainer,
|
List: ListContainer,
|
||||||
}}
|
}}
|
||||||
scrollerRef={setScroller}
|
scrollerRef={setScroller}
|
||||||
itemContent={(index, item) => {
|
itemContent={(index, item) => (
|
||||||
if (isImageDTO(item)) {
|
|
||||||
return (
|
|
||||||
<HoverableImage
|
<HoverableImage
|
||||||
key={`${item.image_name}-${item.thumbnail_url}`}
|
key={`${item.image_name}-${item.thumbnail_url}`}
|
||||||
image={item}
|
image={item}
|
||||||
@ -395,13 +377,7 @@ const ImageGalleryContent = () => {
|
|||||||
selectedImage?.image_name === item?.image_name
|
selectedImage?.image_name === item?.image_name
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
)}
|
||||||
} else if (isBoardDTO(item)) {
|
|
||||||
return (
|
|
||||||
<HoverableBoard key={item.board_id} board={item} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -8,7 +8,12 @@ import {
|
|||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { BoardDTO } from 'services/api';
|
import { BoardDTO } from 'services/api';
|
||||||
import { dateComparator } from 'common/util/dateComparator';
|
import { dateComparator } from 'common/util/dateComparator';
|
||||||
import { receivedBoards } from '../../../services/thunks/board';
|
import {
|
||||||
|
boardCreated,
|
||||||
|
boardDeleted,
|
||||||
|
boardUpdated,
|
||||||
|
receivedBoards,
|
||||||
|
} from '../../../services/thunks/board';
|
||||||
|
|
||||||
export const boardsAdapter = createEntityAdapter<BoardDTO>({
|
export const boardsAdapter = createEntityAdapter<BoardDTO>({
|
||||||
selectId: (board) => board.board_id,
|
selectId: (board) => board.board_id,
|
||||||
@ -26,7 +31,7 @@ type AdditionalBoardsState = {
|
|||||||
export const initialBoardsState =
|
export const initialBoardsState =
|
||||||
boardsAdapter.getInitialState<AdditionalBoardsState>({
|
boardsAdapter.getInitialState<AdditionalBoardsState>({
|
||||||
offset: 0,
|
offset: 0,
|
||||||
limit: 0,
|
limit: 50,
|
||||||
total: 0,
|
total: 0,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
selectedBoardId: null,
|
selectedBoardId: null,
|
||||||
@ -47,7 +52,7 @@ const boardsSlice = createSlice({
|
|||||||
boardRemoved: (state, action: PayloadAction<string>) => {
|
boardRemoved: (state, action: PayloadAction<string>) => {
|
||||||
boardsAdapter.removeOne(state, action.payload);
|
boardsAdapter.removeOne(state, action.payload);
|
||||||
},
|
},
|
||||||
boardIdSelected: (state, action: PayloadAction<string>) => {
|
boardIdSelected: (state, action: PayloadAction<string | null>) => {
|
||||||
state.selectedBoardId = action.payload;
|
state.selectedBoardId = action.payload;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -66,6 +71,19 @@ const boardsSlice = createSlice({
|
|||||||
state.total = total;
|
state.total = total;
|
||||||
boardsAdapter.upsertMany(state, items);
|
boardsAdapter.upsertMany(state, items);
|
||||||
});
|
});
|
||||||
|
builder.addCase(boardCreated.fulfilled, (state, action) => {
|
||||||
|
const board = action.payload;
|
||||||
|
boardsAdapter.upsertOne(state, board);
|
||||||
|
});
|
||||||
|
builder.addCase(boardUpdated.fulfilled, (state, action) => {
|
||||||
|
const board = action.payload;
|
||||||
|
boardsAdapter.upsertOne(state, board);
|
||||||
|
});
|
||||||
|
builder.addCase(boardDeleted.pending, (state, action) => {
|
||||||
|
const boardId = action.meta.arg;
|
||||||
|
console.log({ boardId });
|
||||||
|
boardsAdapter.removeOne(state, boardId);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -21,3 +21,21 @@ export const boardCreated = createAppAsyncThunk(
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const boardDeleted = createAppAsyncThunk(
|
||||||
|
'api/boardDeleted',
|
||||||
|
async (boardId: string) => {
|
||||||
|
await BoardsService.deleteBoard({ boardId });
|
||||||
|
return boardId;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
type BoardUpdatedArg = Parameters<(typeof BoardsService)['updateBoard']>[0];
|
||||||
|
|
||||||
|
export const boardUpdated = createAppAsyncThunk(
|
||||||
|
'api/boardUpdated',
|
||||||
|
async (arg: BoardUpdatedArg) => {
|
||||||
|
const response = await BoardsService.updateBoard(arg);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user