Merge pull request #728 from ente-io/photoswipe-delete-file-option
Photoswipe delete file option
This commit is contained in:
commit
677c7e88c4
|
@ -1,6 +1,6 @@
|
||||||
import { GalleryContext } from 'pages/gallery';
|
import { GalleryContext } from 'pages/gallery';
|
||||||
import PreviewCard from './pages/gallery/PreviewCard';
|
import PreviewCard from './pages/gallery/PreviewCard';
|
||||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import { EnteFile } from 'types/file';
|
import { EnteFile } from 'types/file';
|
||||||
import { styled } from '@mui/material';
|
import { styled } from '@mui/material';
|
||||||
import DownloadManager from 'services/downloadManager';
|
import DownloadManager from 'services/downloadManager';
|
||||||
|
@ -30,6 +30,7 @@ import { logError } from 'utils/sentry';
|
||||||
import { CustomError } from 'utils/error';
|
import { CustomError } from 'utils/error';
|
||||||
import { User } from 'types/user';
|
import { User } from 'types/user';
|
||||||
import { getData, LS_KEYS } from 'utils/storage/localStorage';
|
import { getData, LS_KEYS } from 'utils/storage/localStorage';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
const Container = styled('div')`
|
const Container = styled('div')`
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -60,7 +61,8 @@ interface Props {
|
||||||
openUploader?;
|
openUploader?;
|
||||||
isInSearchMode?: boolean;
|
isInSearchMode?: boolean;
|
||||||
search?: Search;
|
search?: Search;
|
||||||
deleted?: number[];
|
deletedFileIds?: Set<number>;
|
||||||
|
setDeletedFileIds?: (value: Set<number>) => void;
|
||||||
activeCollection: number;
|
activeCollection: number;
|
||||||
isSharedCollection?: boolean;
|
isSharedCollection?: boolean;
|
||||||
enableDownload?: boolean;
|
enableDownload?: boolean;
|
||||||
|
@ -86,7 +88,8 @@ const PhotoFrame = ({
|
||||||
isInSearchMode,
|
isInSearchMode,
|
||||||
search,
|
search,
|
||||||
resetSearch,
|
resetSearch,
|
||||||
deleted,
|
deletedFileIds,
|
||||||
|
setDeletedFileIds,
|
||||||
activeCollection,
|
activeCollection,
|
||||||
isSharedCollection,
|
isSharedCollection,
|
||||||
enableDownload,
|
enableDownload,
|
||||||
|
@ -104,67 +107,14 @@ const PhotoFrame = ({
|
||||||
const [rangeStart, setRangeStart] = useState(null);
|
const [rangeStart, setRangeStart] = useState(null);
|
||||||
const [currentHover, setCurrentHover] = useState(null);
|
const [currentHover, setCurrentHover] = useState(null);
|
||||||
const [isShiftKeyPressed, setIsShiftKeyPressed] = useState(false);
|
const [isShiftKeyPressed, setIsShiftKeyPressed] = useState(false);
|
||||||
const filteredDataRef = useRef<EnteFile[]>([]);
|
|
||||||
const filteredData = filteredDataRef?.current ?? [];
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [isSourceLoaded, setIsSourceLoaded] = useState(false);
|
const [isSourceLoaded, setIsSourceLoaded] = useState(false);
|
||||||
useEffect(() => {
|
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
|
||||||
if (e.key === 'Shift') {
|
|
||||||
setIsShiftKeyPressed(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleKeyUp = (e: KeyboardEvent) => {
|
|
||||||
if (e.key === 'Shift') {
|
|
||||||
setIsShiftKeyPressed(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
document.addEventListener('keydown', handleKeyDown, false);
|
|
||||||
document.addEventListener('keyup', handleKeyUp, false);
|
|
||||||
router.events.on('hashChangeComplete', (url: string) => {
|
|
||||||
const start = url.indexOf('#');
|
|
||||||
const hash = url.slice(start !== -1 ? start : url.length);
|
|
||||||
const shouldPhotoSwipeBeOpened = hash.endsWith(
|
|
||||||
PHOTOSWIPE_HASH_SUFFIX
|
|
||||||
);
|
|
||||||
if (shouldPhotoSwipeBeOpened) {
|
|
||||||
setOpen(true);
|
|
||||||
} else {
|
|
||||||
setOpen(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return () => {
|
|
||||||
document.addEventListener('keydown', handleKeyDown, false);
|
|
||||||
document.addEventListener('keyup', handleKeyUp, false);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
const filteredData = useMemo(() => {
|
||||||
if (!isNaN(search?.file)) {
|
|
||||||
const filteredDataIdx = filteredData.findIndex((file) => {
|
|
||||||
return file.id === search.file;
|
|
||||||
});
|
|
||||||
if (!isNaN(filteredDataIdx)) {
|
|
||||||
onThumbnailClick(filteredDataIdx)();
|
|
||||||
}
|
|
||||||
resetSearch();
|
|
||||||
}
|
|
||||||
}, [search, filteredData]);
|
|
||||||
|
|
||||||
const resetFetching = () => {
|
|
||||||
setFetching({});
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (selected.count === 0) {
|
|
||||||
setRangeStart(null);
|
|
||||||
}
|
|
||||||
}, [selected]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const idSet = new Set();
|
const idSet = new Set();
|
||||||
const user: User = getData(LS_KEYS.USER);
|
const user: User = getData(LS_KEYS.USER);
|
||||||
filteredDataRef.current = files
|
|
||||||
|
return files
|
||||||
.map((item, index) => ({
|
.map((item, index) => ({
|
||||||
...item,
|
...item,
|
||||||
dataIndex: index,
|
dataIndex: index,
|
||||||
|
@ -172,7 +122,10 @@ const PhotoFrame = ({
|
||||||
h: window.innerHeight,
|
h: window.innerHeight,
|
||||||
}))
|
}))
|
||||||
.filter((item) => {
|
.filter((item) => {
|
||||||
if (deleted?.includes(item.id)) {
|
if (
|
||||||
|
deletedFileIds?.has(item.id) &&
|
||||||
|
activeCollection !== TRASH_SECTION
|
||||||
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
|
@ -230,7 +183,7 @@ const PhotoFrame = ({
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}, [files, deleted, search, activeCollection]);
|
}, [files, deletedFileIds, search, activeCollection]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const currentURL = new URL(window.location.href);
|
const currentURL = new URL(window.location.href);
|
||||||
|
@ -247,6 +200,59 @@ const PhotoFrame = ({
|
||||||
}
|
}
|
||||||
}, [open]);
|
}, [open]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
|
if (e.key === 'Shift') {
|
||||||
|
setIsShiftKeyPressed(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleKeyUp = (e: KeyboardEvent) => {
|
||||||
|
if (e.key === 'Shift') {
|
||||||
|
setIsShiftKeyPressed(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.addEventListener('keydown', handleKeyDown, false);
|
||||||
|
document.addEventListener('keyup', handleKeyUp, false);
|
||||||
|
router.events.on('hashChangeComplete', (url: string) => {
|
||||||
|
const start = url.indexOf('#');
|
||||||
|
const hash = url.slice(start !== -1 ? start : url.length);
|
||||||
|
const shouldPhotoSwipeBeOpened = hash.endsWith(
|
||||||
|
PHOTOSWIPE_HASH_SUFFIX
|
||||||
|
);
|
||||||
|
if (shouldPhotoSwipeBeOpened) {
|
||||||
|
setOpen(true);
|
||||||
|
} else {
|
||||||
|
setOpen(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
document.addEventListener('keydown', handleKeyDown, false);
|
||||||
|
document.addEventListener('keyup', handleKeyUp, false);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isNaN(search?.file)) {
|
||||||
|
const filteredDataIdx = filteredData.findIndex((file) => {
|
||||||
|
return file.id === search.file;
|
||||||
|
});
|
||||||
|
if (!isNaN(filteredDataIdx)) {
|
||||||
|
onThumbnailClick(filteredDataIdx)();
|
||||||
|
}
|
||||||
|
resetSearch();
|
||||||
|
}
|
||||||
|
}, [search, filteredData]);
|
||||||
|
|
||||||
|
const resetFetching = () => {
|
||||||
|
setFetching({});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selected.count === 0) {
|
||||||
|
setRangeStart(null);
|
||||||
|
}
|
||||||
|
}, [selected]);
|
||||||
|
|
||||||
const getFileIndexFromID = (files: EnteFile[], id: number) => {
|
const getFileIndexFromID = (files: EnteFile[], id: number) => {
|
||||||
const index = files.findIndex((file) => file.id === id);
|
const index = files.findIndex((file) => file.id === id);
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
|
@ -603,6 +609,8 @@ const PhotoFrame = ({
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
gettingData={getSlideData}
|
gettingData={getSlideData}
|
||||||
favItemIds={favItemIds}
|
favItemIds={favItemIds}
|
||||||
|
deletedFileIds={deletedFileIds}
|
||||||
|
setDeletedFileIds={setDeletedFileIds}
|
||||||
isSharedCollection={isSharedCollection}
|
isSharedCollection={isSharedCollection}
|
||||||
isTrashCollection={activeCollection === TRASH_SECTION}
|
isTrashCollection={activeCollection === TRASH_SECTION}
|
||||||
enableDownload={enableDownload}
|
enableDownload={enableDownload}
|
||||||
|
|
|
@ -247,6 +247,8 @@ export function PhotoList({
|
||||||
filteredData,
|
filteredData,
|
||||||
showAppDownloadBanner,
|
showAppDownloadBanner,
|
||||||
publicCollectionGalleryContext.accessedThroughSharedURL,
|
publicCollectionGalleryContext.accessedThroughSharedURL,
|
||||||
|
galleryContext.photoListHeader,
|
||||||
|
publicCollectionGalleryContext.photoListHeader,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const groupByFileSize = (timeStampList: TimeStampListItem[]) => {
|
const groupByFileSize = (timeStampList: TimeStampListItem[]) => {
|
||||||
|
|
|
@ -28,6 +28,9 @@ import InfoIcon from '@mui/icons-material/InfoOutlined';
|
||||||
import FavoriteIcon from '@mui/icons-material/FavoriteRounded';
|
import FavoriteIcon from '@mui/icons-material/FavoriteRounded';
|
||||||
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorderRounded';
|
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorderRounded';
|
||||||
import ChevronRight from '@mui/icons-material/ChevronRight';
|
import ChevronRight from '@mui/icons-material/ChevronRight';
|
||||||
|
import DeleteIcon from '@mui/icons-material/Delete';
|
||||||
|
import { trashFiles } from 'services/fileService';
|
||||||
|
import { getTrashFileMessage } from 'utils/ui';
|
||||||
|
|
||||||
interface Iprops {
|
interface Iprops {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
|
@ -38,6 +41,8 @@ interface Iprops {
|
||||||
id?: string;
|
id?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
favItemIds: Set<number>;
|
favItemIds: Set<number>;
|
||||||
|
deletedFileIds: Set<number>;
|
||||||
|
setDeletedFileIds?: (value: Set<number>) => void;
|
||||||
isSharedCollection: boolean;
|
isSharedCollection: boolean;
|
||||||
isTrashCollection: boolean;
|
isTrashCollection: boolean;
|
||||||
enableDownload: boolean;
|
enableDownload: boolean;
|
||||||
|
@ -262,6 +267,17 @@ function PhotoSwipe(props: Iprops) {
|
||||||
needUpdate.current = true;
|
needUpdate.current = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const trashFile = async (file: EnteFile) => {
|
||||||
|
const { deletedFileIds, setDeletedFileIds } = props;
|
||||||
|
deletedFileIds.add(file.id);
|
||||||
|
setDeletedFileIds(new Set(deletedFileIds));
|
||||||
|
await trashFiles([file]);
|
||||||
|
needUpdate.current = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmTrashFile = (file: EnteFile) =>
|
||||||
|
appContext.setDialogMessage(getTrashFileMessage(() => trashFile(file)));
|
||||||
|
|
||||||
const updateItems = (items = []) => {
|
const updateItems = (items = []) => {
|
||||||
if (photoSwipe) {
|
if (photoSwipe) {
|
||||||
photoSwipe.items.length = 0;
|
photoSwipe.items.length = 0;
|
||||||
|
@ -269,7 +285,9 @@ function PhotoSwipe(props: Iprops) {
|
||||||
photoSwipe.items.push(item);
|
photoSwipe.items.push(item);
|
||||||
});
|
});
|
||||||
photoSwipe.invalidateCurrItems();
|
photoSwipe.invalidateCurrItems();
|
||||||
// photoSwipe.updateSize(true);
|
if (isOpen) {
|
||||||
|
photoSwipe.updateSize(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -357,6 +375,16 @@ function PhotoSwipe(props: Iprops) {
|
||||||
className="pswp__button pswp__button--close"
|
className="pswp__button pswp__button--close"
|
||||||
title={constants.CLOSE}
|
title={constants.CLOSE}
|
||||||
/>
|
/>
|
||||||
|
<button
|
||||||
|
className="pswp__button pswp__button--custom"
|
||||||
|
title={constants.DELETE}
|
||||||
|
onClick={() => {
|
||||||
|
confirmTrashFile(
|
||||||
|
photoSwipe?.currItem as EnteFile
|
||||||
|
);
|
||||||
|
}}>
|
||||||
|
<DeleteIcon fontSize="small" />
|
||||||
|
</button>
|
||||||
|
|
||||||
{props.enableDownload && (
|
{props.enableDownload && (
|
||||||
<button
|
<button
|
||||||
|
@ -379,6 +407,11 @@ function PhotoSwipe(props: Iprops) {
|
||||||
{!props.isSharedCollection &&
|
{!props.isSharedCollection &&
|
||||||
!props.isTrashCollection && (
|
!props.isTrashCollection && (
|
||||||
<button
|
<button
|
||||||
|
title={
|
||||||
|
isFav
|
||||||
|
? constants.UNFAVORITE
|
||||||
|
: constants.FAVORITE
|
||||||
|
}
|
||||||
className="pswp__button pswp__button--custom"
|
className="pswp__button pswp__button--custom"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onFavClick(photoSwipe?.currItem);
|
onFavClick(photoSwipe?.currItem);
|
||||||
|
@ -390,6 +423,7 @@ function PhotoSwipe(props: Iprops) {
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!props.isSharedCollection && (
|
{!props.isSharedCollection && (
|
||||||
<button
|
<button
|
||||||
className="pswp__button pswp__button--custom"
|
className="pswp__button pswp__button--custom"
|
||||||
|
|
|
@ -265,6 +265,7 @@ export default function App({ Component, err }) {
|
||||||
<LoadingBar color="#51cd7c" ref={loadingBar} />
|
<LoadingBar color="#51cd7c" ref={loadingBar} />
|
||||||
|
|
||||||
<DialogBox
|
<DialogBox
|
||||||
|
sx={{ zIndex: 1600 }}
|
||||||
size="xs"
|
size="xs"
|
||||||
open={messageDialogView}
|
open={messageDialogView}
|
||||||
onClose={closeMessageDialog}
|
onClose={closeMessageDialog}
|
||||||
|
|
|
@ -180,7 +180,9 @@ export default function Gallery() {
|
||||||
useState<SearchResultSummary>(null);
|
useState<SearchResultSummary>(null);
|
||||||
const syncInProgress = useRef(true);
|
const syncInProgress = useRef(true);
|
||||||
const resync = useRef(false);
|
const resync = useRef(false);
|
||||||
const [deleted, setDeleted] = useState<number[]>([]);
|
const [deletedFileIds, setDeletedFileIds] = useState<Set<number>>(
|
||||||
|
new Set<number>()
|
||||||
|
);
|
||||||
const { startLoading, finishLoading, setDialogMessage, ...appContext } =
|
const { startLoading, finishLoading, setDialogMessage, ...appContext } =
|
||||||
useContext(AppContext);
|
useContext(AppContext);
|
||||||
const [collectionSummaries, setCollectionSummaries] =
|
const [collectionSummaries, setCollectionSummaries] =
|
||||||
|
@ -490,12 +492,12 @@ export default function Gallery() {
|
||||||
startLoading();
|
startLoading();
|
||||||
try {
|
try {
|
||||||
const selectedFiles = getSelectedFiles(selected, files);
|
const selectedFiles = getSelectedFiles(selected, files);
|
||||||
|
setDeletedFileIds((deletedFileIds) => {
|
||||||
|
selectedFiles.forEach((file) => deletedFileIds.add(file.id));
|
||||||
|
return new Set(deletedFileIds);
|
||||||
|
});
|
||||||
if (permanent) {
|
if (permanent) {
|
||||||
await deleteFromTrash(selectedFiles.map((file) => file.id));
|
await deleteFromTrash(selectedFiles.map((file) => file.id));
|
||||||
setDeleted([
|
|
||||||
...deleted,
|
|
||||||
...selectedFiles.map((file) => file.id),
|
|
||||||
]);
|
|
||||||
} else {
|
} else {
|
||||||
await trashFiles(selectedFiles);
|
await trashFiles(selectedFiles);
|
||||||
}
|
}
|
||||||
|
@ -698,7 +700,8 @@ export default function Gallery() {
|
||||||
openUploader={openUploader}
|
openUploader={openUploader}
|
||||||
isInSearchMode={isInSearchMode}
|
isInSearchMode={isInSearchMode}
|
||||||
search={search}
|
search={search}
|
||||||
deleted={deleted}
|
deletedFileIds={deletedFileIds}
|
||||||
|
setDeletedFileIds={setDeletedFileIds}
|
||||||
activeCollection={activeCollection}
|
activeCollection={activeCollection}
|
||||||
isSharedCollection={isSharedCollection(
|
isSharedCollection={isSharedCollection(
|
||||||
activeCollection,
|
activeCollection,
|
||||||
|
|
|
@ -318,7 +318,7 @@ export default function PublicCollectionGallery() {
|
||||||
openUploader={() => null}
|
openUploader={() => null}
|
||||||
isInSearchMode={false}
|
isInSearchMode={false}
|
||||||
search={{}}
|
search={{}}
|
||||||
deleted={[]}
|
deletedFileIds={new Set<number>()}
|
||||||
activeCollection={ALL_SECTION}
|
activeCollection={ALL_SECTION}
|
||||||
isSharedCollection
|
isSharedCollection
|
||||||
enableDownload={
|
enableDownload={
|
||||||
|
|
|
@ -147,14 +147,15 @@ const englishConstants = {
|
||||||
UPLOAD_FIRST_PHOTO: 'Preserve',
|
UPLOAD_FIRST_PHOTO: 'Preserve',
|
||||||
UPLOAD_DROPZONE_MESSAGE: 'Drop to backup your files',
|
UPLOAD_DROPZONE_MESSAGE: 'Drop to backup your files',
|
||||||
WATCH_FOLDER_DROPZONE_MESSAGE: 'Drop to add watched folder',
|
WATCH_FOLDER_DROPZONE_MESSAGE: 'Drop to add watched folder',
|
||||||
CONFIRM_DELETE: 'Confirm deletion',
|
|
||||||
DELETE_MESSAGE: `The selected files will be permanently deleted and can't be restored `,
|
|
||||||
TRASH_FILES_TITLE: 'Delete files?',
|
TRASH_FILES_TITLE: 'Delete files?',
|
||||||
|
TRASH_FILE_TITLE: 'Delete file?',
|
||||||
DELETE_FILES_TITLE: 'Delete immediately?',
|
DELETE_FILES_TITLE: 'Delete immediately?',
|
||||||
DELETE_FILES_MESSAGE:
|
DELETE_FILES_MESSAGE:
|
||||||
'Selected files will be permanently deleted from your ente account.',
|
'Selected files will be permanently deleted from your ente account.',
|
||||||
DELETE_FILE: 'Delete files',
|
DELETE_FILE: 'Delete files',
|
||||||
DELETE: 'Delete',
|
DELETE: 'Delete',
|
||||||
|
FAVORITE: 'Favorite',
|
||||||
|
UNFAVORITE: 'Unfavorite',
|
||||||
MULTI_FOLDER_UPLOAD: 'Multiple folders detected',
|
MULTI_FOLDER_UPLOAD: 'Multiple folders detected',
|
||||||
UPLOAD_STRATEGY_CHOICE: 'Would you like to upload them into',
|
UPLOAD_STRATEGY_CHOICE: 'Would you like to upload them into',
|
||||||
UPLOAD_STRATEGY_SINGLE_COLLECTION: 'A single album',
|
UPLOAD_STRATEGY_SINGLE_COLLECTION: 'A single album',
|
||||||
|
@ -569,6 +570,8 @@ const englishConstants = {
|
||||||
MOVE_TO_TRASH: 'Move to trash',
|
MOVE_TO_TRASH: 'Move to trash',
|
||||||
TRASH_FILES_MESSAGE:
|
TRASH_FILES_MESSAGE:
|
||||||
'Selected files will be removed from all albums and moved to trash.',
|
'Selected files will be removed from all albums and moved to trash.',
|
||||||
|
TRASH_FILE_MESSAGE:
|
||||||
|
'The file will be removed from all albums and moved to trash.',
|
||||||
DELETE_PERMANENTLY: 'Delete permanently',
|
DELETE_PERMANENTLY: 'Delete permanently',
|
||||||
RESTORE: 'Restore',
|
RESTORE: 'Restore',
|
||||||
CONFIRM_RESTORE: 'Confirm restoration',
|
CONFIRM_RESTORE: 'Confirm restoration',
|
||||||
|
|
|
@ -30,3 +30,14 @@ export const getTrashFilesMessage = (
|
||||||
},
|
},
|
||||||
close: { text: constants.CANCEL },
|
close: { text: constants.CANCEL },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const getTrashFileMessage = (deleteFileHelper): DialogBoxAttributes => ({
|
||||||
|
title: constants.TRASH_FILE_TITLE,
|
||||||
|
content: constants.TRASH_FILE_MESSAGE,
|
||||||
|
proceed: {
|
||||||
|
action: deleteFileHelper,
|
||||||
|
text: constants.MOVE_TO_TRASH,
|
||||||
|
variant: 'danger',
|
||||||
|
},
|
||||||
|
close: { text: constants.CANCEL },
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in a new issue