refactored selectedFileOptions utils to file util

This commit is contained in:
Abhinav 2023-07-24 17:25:47 +05:30
parent a00e2d7b16
commit aea2a747f0
3 changed files with 171 additions and 186 deletions

View file

@ -11,7 +11,6 @@ import {
HIDDEN_SECTION,
TRASH_SECTION,
} from 'constants/collection';
import { Collection } from 'types/collection';
import { SelectionBar } from '../../Navbar/SelectionBar';
import { AppContext } from 'pages/_app';
import { Box, IconButton, Stack, Tooltip } from '@mui/material';
@ -30,24 +29,18 @@ import { t } from 'i18next';
import { formatNumber } from 'utils/number/format';
import VisibilityOffOutlined from '@mui/icons-material/VisibilityOffOutlined';
import VisibilityOutlined from '@mui/icons-material/VisibilityOutlined';
import { FILE_OPS_TYPE } from 'utils/file';
interface Props {
addToCollectionHelper: (collection: Collection) => void;
moveToCollectionHelper: (collection: Collection) => void;
restoreToCollectionHelper: (collection: Collection) => void;
unhideToCollectionHelper: (collection: Collection) => void;
handleCollectionOps: (
opsType: COLLECTION_OPS_TYPE
) => (...args: any[]) => void;
handleFileOps: (opsType: FILE_OPS_TYPE) => (...args: any[]) => void;
showCreateCollectionModal: (opsType: COLLECTION_OPS_TYPE) => () => void;
setCollectionSelectorAttributes: SetCollectionSelectorAttributes;
deleteFileHelper: (permanent?: boolean) => void;
hideFilesHelper: () => void;
removeFromCollectionHelper: () => void;
fixTimeHelper: () => void;
downloadHelper: () => void;
count: number;
ownCount: number;
clearSelection: () => void;
archiveFilesHelper: () => void;
unArchiveFilesHelper: () => void;
activeCollection: number;
isFavoriteCollection: boolean;
isUncategorizedCollection: boolean;
@ -56,22 +49,13 @@ interface Props {
}
const SelectedFileOptions = ({
addToCollectionHelper,
moveToCollectionHelper,
restoreToCollectionHelper,
showCreateCollectionModal,
removeFromCollectionHelper,
unhideToCollectionHelper,
fixTimeHelper,
setCollectionSelectorAttributes,
deleteFileHelper,
hideFilesHelper,
downloadHelper,
handleCollectionOps,
handleFileOps,
count,
ownCount,
clearSelection,
archiveFilesHelper,
unArchiveFilesHelper,
activeCollection,
isFavoriteCollection,
isUncategorizedCollection,
@ -81,21 +65,23 @@ const SelectedFileOptions = ({
const { setDialogMessage } = useContext(AppContext);
const addToCollection = () =>
setCollectionSelectorAttributes({
callback: addToCollectionHelper,
callback: handleCollectionOps(COLLECTION_OPS_TYPE.ADD),
showNextModal: showCreateCollectionModal(COLLECTION_OPS_TYPE.ADD),
intent: CollectionSelectorIntent.add,
fromCollection: !isInSearchMode ? activeCollection : undefined,
});
const trashHandler = () =>
setDialogMessage(getTrashFilesMessage(deleteFileHelper));
setDialogMessage(
getTrashFilesMessage(handleFileOps(FILE_OPS_TYPE.TRASH))
);
const permanentlyDeleteHandler = () =>
setDialogMessage({
title: t('DELETE_FILES_TITLE'),
content: t('DELETE_FILES_MESSAGE'),
proceed: {
action: () => deleteFileHelper(true),
action: handleFileOps(FILE_OPS_TYPE.DELETE_PERMANENTLY),
text: t('DELETE'),
variant: 'critical',
},
@ -104,7 +90,7 @@ const SelectedFileOptions = ({
const restoreHandler = () =>
setCollectionSelectorAttributes({
callback: restoreToCollectionHelper,
callback: handleCollectionOps(COLLECTION_OPS_TYPE.RESTORE),
showNextModal: showCreateCollectionModal(
COLLECTION_OPS_TYPE.RESTORE
),
@ -118,7 +104,7 @@ const SelectedFileOptions = ({
content: t('CONFIRM_SELF_REMOVE_MESSAGE'),
proceed: {
action: removeFromCollectionHelper,
action: handleCollectionOps(COLLECTION_OPS_TYPE.REMOVE),
text: t('YES_REMOVE'),
variant: 'primary',
},
@ -130,7 +116,7 @@ const SelectedFileOptions = ({
content: t('CONFIRM_SELF_AND_OTHER_REMOVE_MESSAGE'),
proceed: {
action: removeFromCollectionHelper,
action: handleCollectionOps(COLLECTION_OPS_TYPE.REMOVE),
text: t('YES_REMOVE'),
variant: 'critical',
},
@ -141,7 +127,7 @@ const SelectedFileOptions = ({
const moveToCollection = () => {
setCollectionSelectorAttributes({
callback: moveToCollectionHelper,
callback: handleCollectionOps(COLLECTION_OPS_TYPE.MOVE),
showNextModal: showCreateCollectionModal(COLLECTION_OPS_TYPE.MOVE),
intent: CollectionSelectorIntent.move,
fromCollection: !isInSearchMode ? activeCollection : undefined,
@ -150,7 +136,7 @@ const SelectedFileOptions = ({
const unhideToCollection = () => {
setCollectionSelectorAttributes({
callback: unhideToCollectionHelper,
callback: handleCollectionOps(COLLECTION_OPS_TYPE.UNHIDE),
showNextModal: showCreateCollectionModal(
COLLECTION_OPS_TYPE.UNHIDE
),
@ -174,12 +160,14 @@ const SelectedFileOptions = ({
{isInSearchMode ? (
<>
<Tooltip title={t('FIX_CREATION_TIME')}>
<IconButton onClick={fixTimeHelper}>
<IconButton
onClick={handleFileOps(FILE_OPS_TYPE.FIX_TIME)}>
<ClockIcon />
</IconButton>
</Tooltip>
<Tooltip title={t('DOWNLOAD')}>
<IconButton onClick={downloadHelper}>
<IconButton
onClick={handleFileOps(FILE_OPS_TYPE.DOWNLOAD)}>
<DownloadIcon />
</IconButton>
</Tooltip>
@ -189,12 +177,14 @@ const SelectedFileOptions = ({
</IconButton>
</Tooltip>
<Tooltip title={t('ARCHIVE')}>
<IconButton onClick={archiveFilesHelper}>
<IconButton
onClick={handleFileOps(FILE_OPS_TYPE.ARCHIVE)}>
<ArchiveIcon />
</IconButton>
</Tooltip>
<Tooltip title={t('HIDE')}>
<IconButton onClick={hideFilesHelper}>
<IconButton
onClick={handleFileOps(FILE_OPS_TYPE.HIDE)}>
<VisibilityOffOutlined />
</IconButton>
</Tooltip>
@ -215,7 +205,8 @@ const SelectedFileOptions = ({
) : isUncategorizedCollection ? (
<>
<Tooltip title={t('DOWNLOAD')}>
<IconButton onClick={downloadHelper}>
<IconButton
onClick={handleFileOps(FILE_OPS_TYPE.DOWNLOAD)}>
<DownloadIcon />
</IconButton>
</Tooltip>
@ -232,7 +223,8 @@ const SelectedFileOptions = ({
</>
) : isIncomingSharedCollection ? (
<Tooltip title={t('DOWNLOAD')}>
<IconButton onClick={downloadHelper}>
<IconButton
onClick={handleFileOps(FILE_OPS_TYPE.DOWNLOAD)}>
<DownloadIcon />
</IconButton>
</Tooltip>
@ -244,7 +236,8 @@ const SelectedFileOptions = ({
</IconButton>
</Tooltip>
<Tooltip title={t('DOWNLOAD')}>
<IconButton onClick={downloadHelper}>
<IconButton
onClick={handleFileOps(FILE_OPS_TYPE.DOWNLOAD)}>
<DownloadIcon />
</IconButton>
</Tooltip>
@ -258,12 +251,14 @@ const SelectedFileOptions = ({
) : (
<>
<Tooltip title={t('FIX_CREATION_TIME')}>
<IconButton onClick={fixTimeHelper}>
<IconButton
onClick={handleFileOps(FILE_OPS_TYPE.FIX_TIME)}>
<ClockIcon />
</IconButton>
</Tooltip>
<Tooltip title={t('DOWNLOAD')}>
<IconButton onClick={downloadHelper}>
<IconButton
onClick={handleFileOps(FILE_OPS_TYPE.DOWNLOAD)}>
<DownloadIcon />
</IconButton>
</Tooltip>
@ -274,14 +269,20 @@ const SelectedFileOptions = ({
</Tooltip>
{activeCollection === ARCHIVE_SECTION && (
<Tooltip title={t('UNARCHIVE')}>
<IconButton onClick={unArchiveFilesHelper}>
<IconButton
onClick={handleFileOps(
FILE_OPS_TYPE.UNARCHIVE
)}>
<UnArchiveIcon />
</IconButton>
</Tooltip>
)}
{activeCollection === ALL_SECTION && (
<Tooltip title={t('ARCHIVE')}>
<IconButton onClick={archiveFilesHelper}>
<IconButton
onClick={handleFileOps(
FILE_OPS_TYPE.ARCHIVE
)}>
<ArchiveIcon />
</IconButton>
</Tooltip>
@ -307,7 +308,8 @@ const SelectedFileOptions = ({
</>
)}
<Tooltip title={t('HIDE')}>
<IconButton onClick={hideFilesHelper}>
<IconButton
onClick={handleFileOps(FILE_OPS_TYPE.HIDE)}>
<VisibilityOffOutlined />
</IconButton>
</Tooltip>

View file

@ -11,8 +11,6 @@ import { clearKeys, getKey, SESSION_KEYS } from 'utils/storage/sessionStorage';
import {
getLocalFiles,
syncFiles,
trashFiles,
deleteFromTrash,
getLocalHiddenFiles,
syncHiddenFiles,
} from 'services/fileService';
@ -23,7 +21,6 @@ import {
getLocalCollections,
createAlbum,
getCollectionSummaries,
moveToHiddenCollection,
constructEmailList,
} from 'services/collectionService';
import { t } from 'i18next';
@ -49,11 +46,11 @@ import EnteSpinner from 'components/EnteSpinner';
import { LoadingOverlay } from 'components/LoadingOverlay';
import PhotoFrame from 'components/PhotoFrame';
import {
changeFilesVisibility,
FILE_OPS_TYPE,
constructFileToCollectionMap,
downloadFiles,
getSelectedFiles,
getUniqueFiles,
handleFileOps,
mergeMetadata,
sortFiles,
} from 'utils/file';
@ -81,7 +78,6 @@ import { PAGES } from 'constants/pages';
import {
COLLECTION_OPS_TYPE,
handleCollectionOps,
getSelectedCollection,
getArchivedCollections,
hasNonSystemCollections,
splitNormalAndHiddenCollections,
@ -100,7 +96,6 @@ import {
SelectedState,
UploadTypeSelectorIntent,
} from 'types/gallery';
import { VISIBILITY_STATE } from 'types/magicMetadata';
import Collections from 'components/Collections';
import { GalleryNavbar } from 'components/pages/gallery/Navbar';
import { Search, SearchResultSummary, UpdateSearch } from 'types/search';
@ -721,26 +716,26 @@ export default function Gallery() {
}
};
const changeFilesVisibilityHelper = async (
visibility: VISIBILITY_STATE
) => {
const fileOpsHelper = (ops: FILE_OPS_TYPE) => async () => {
startLoading();
try {
const selectedFiles = getSelectedFiles(selected, filteredData);
await changeFilesVisibility(selectedFiles, visibility);
clearSelection();
} catch (e) {
logError(e, 'change file visibility failed');
switch (e.status?.toString()) {
case ServerErrorCodes.FORBIDDEN:
setDialogMessage({
title: t('ERROR'),
close: { variant: 'critical' },
content: t('NOT_FILE_OWNER'),
});
return;
const toProcessFiles = selectedFiles.filter(
(file) => file.ownerID === user.id
);
if (toProcessFiles.length > 0) {
await handleFileOps(
ops,
toProcessFiles,
setDeletedFileIds,
setHiddenFileIds,
setFixCreationTimeAttributes
);
}
clearSelection();
await syncWithRemote(false, true);
} catch (e) {
logError(e, 'file ops failed', { ops });
setDialogMessage({
title: t('ERROR'),
@ -748,7 +743,6 @@ export default function Gallery() {
content: t('UNKNOWN_ERROR'),
});
} finally {
await syncWithRemote(false, true);
finishLoading();
}
};
@ -780,77 +774,6 @@ export default function Gallery() {
});
};
const deleteFileHelper = async (permanent?: boolean) => {
startLoading();
try {
const selectedFiles = getSelectedFiles(selected, filteredData);
setDeletedFileIds((deletedFileIds) => {
selectedFiles.forEach((file) => deletedFileIds.add(file.id));
return new Set(deletedFileIds);
});
if (permanent) {
await deleteFromTrash(selectedFiles.map((file) => file.id));
} else {
await trashFiles(selectedFiles);
}
clearSelection();
} catch (e) {
setDeletedFileIds(new Set());
switch (e.status?.toString()) {
case ServerErrorCodes.FORBIDDEN:
setDialogMessage({
title: t('ERROR'),
close: { variant: 'critical' },
content: t('NOT_FILE_OWNER'),
});
}
setDialogMessage({
title: t('ERROR'),
close: { variant: 'critical' },
content: t('UNKNOWN_ERROR'),
});
} finally {
await syncWithRemote(false, true);
finishLoading();
}
};
const hideFilesHelper = async () => {
startLoading();
try {
// passing files here instead of filteredData because we want to move all files copies to hidden collection
const selectedFiles = getSelectedFiles(selected, files);
setHiddenFileIds((hiddenFileIds) => {
selectedFiles.forEach((file) => hiddenFileIds.add(file.id));
return new Set(hiddenFileIds);
});
await moveToHiddenCollection(selectedFiles);
clearSelection();
} catch (e) {
setHiddenFileIds(new Set());
switch (e.status?.toString()) {
case ServerErrorCodes.FORBIDDEN:
setDialogMessage({
title: t('ERROR'),
close: { variant: 'critical' },
content: t('NOT_FILE_OWNER'),
});
}
setDialogMessage({
title: t('ERROR'),
close: { variant: 'critical' },
content: t('UNKNOWN_ERROR'),
});
} finally {
await syncWithRemote(false, true);
finishLoading();
}
};
const updateSearch: UpdateSearch = (newSearch, summary) => {
if (newSearch?.collection) {
setActiveCollection(newSearch?.collection);
@ -865,20 +788,6 @@ export default function Gallery() {
}
};
const fixTimeHelper = async () => {
const selectedFiles = getSelectedFiles(selected, filteredData);
setFixCreationTimeAttributes({ files: selectedFiles });
clearSelection();
};
const downloadHelper = async () => {
const selectedFiles = getSelectedFiles(selected, filteredData);
clearSelection();
startLoading();
await downloadFiles(selectedFiles);
finishLoading();
};
const openUploader = (intent = UploadTypeSelectorIntent.normalUpload) => {
if (!uploadManager.shouldAllowNewUpload()) {
return;
@ -1044,46 +953,14 @@ export default function Gallery() {
{selected.count > 0 &&
selected.collectionID === activeCollection && (
<SelectedFileOptions
addToCollectionHelper={collectionOpsHelper(
COLLECTION_OPS_TYPE.ADD
)}
archiveFilesHelper={() =>
changeFilesVisibilityHelper(
VISIBILITY_STATE.ARCHIVED
)
}
unArchiveFilesHelper={() =>
changeFilesVisibilityHelper(
VISIBILITY_STATE.VISIBLE
)
}
moveToCollectionHelper={collectionOpsHelper(
COLLECTION_OPS_TYPE.MOVE
)}
restoreToCollectionHelper={collectionOpsHelper(
COLLECTION_OPS_TYPE.RESTORE
)}
unhideToCollectionHelper={collectionOpsHelper(
COLLECTION_OPS_TYPE.UNHIDE
)}
handleCollectionOps={collectionOpsHelper}
handleFileOps={fileOpsHelper}
showCreateCollectionModal={
showCreateCollectionModal
}
setCollectionSelectorAttributes={
setCollectionSelectorAttributes
}
deleteFileHelper={deleteFileHelper}
hideFilesHelper={hideFilesHelper}
removeFromCollectionHelper={() =>
collectionOpsHelper(COLLECTION_OPS_TYPE.REMOVE)(
getSelectedCollection(
activeCollection,
collections
)
)
}
fixTimeHelper={fixTimeHelper}
downloadHelper={downloadHelper}
count={selected.count}
ownCount={selected.ownCount}
clearSelection={clearSelection}

View file

@ -35,6 +35,8 @@ import { CustomError } from 'utils/error';
import { convertBytesToHumanReadable } from './size';
import ComlinkCryptoWorker from 'utils/comlink/ComlinkCryptoWorker';
import {
deleteFromTrash,
trashFiles,
updateFileMagicMetadata,
updateFilePublicMagicMetadata,
} from 'services/fileService';
@ -42,9 +44,20 @@ import isElectron from 'is-electron';
import imageProcessor from 'services/electron/imageProcessor';
import { isPlaybackPossible } from 'utils/photoFrame';
import { FileTypeInfo } from 'types/upload';
import { moveToHiddenCollection } from 'services/collectionService';
const WAIT_TIME_IMAGE_CONVERSION = 30 * 1000;
export enum FILE_OPS_TYPE {
DOWNLOAD,
FIX_TIME,
ARCHIVE,
UNARCHIVE,
HIDE,
TRASH,
DELETE_PERMANENTLY,
}
export function downloadAsFile(filename: string, content: string) {
const file = new Blob([content], {
type: 'text/plain',
@ -691,3 +704,96 @@ export const shouldShowAvatar = (file: EnteFile, user: User) => {
return false;
}
};
export const handleFileOps = async (
ops: FILE_OPS_TYPE,
files: EnteFile[],
setDeletedFileIds: (
deletedFileIds: Set<number> | ((prev: Set<number>) => Set<number>)
) => void,
setHiddenFileIds: (
hiddenFileIds: Set<number> | ((prev: Set<number>) => Set<number>)
) => void,
setFixCreationTimeAttributes: (
fixCreationTimeAttributes:
| {
files: EnteFile[];
}
| ((prev: { files: EnteFile[] }) => { files: EnteFile[] })
) => void
) => {
switch (ops) {
case FILE_OPS_TYPE.TRASH:
await deleteFileHelper(files, false, setDeletedFileIds);
break;
case FILE_OPS_TYPE.DELETE_PERMANENTLY:
await deleteFileHelper(files, true, setDeletedFileIds);
break;
case FILE_OPS_TYPE.HIDE:
await hideFilesHelper(files, setHiddenFileIds);
break;
case FILE_OPS_TYPE.DOWNLOAD:
await downloadFiles(files);
break;
case FILE_OPS_TYPE.FIX_TIME:
fixTimeHelper(files, setFixCreationTimeAttributes);
break;
case FILE_OPS_TYPE.ARCHIVE:
await changeFilesVisibility(files, VISIBILITY_STATE.ARCHIVED);
break;
case FILE_OPS_TYPE.UNARCHIVE:
await changeFilesVisibility(files, VISIBILITY_STATE.VISIBLE);
break;
}
};
const deleteFileHelper = async (
selectedFiles: EnteFile[],
permanent: boolean,
setDeletedFileIds: (
deletedFileIds: Set<number> | ((prev: Set<number>) => Set<number>)
) => void
) => {
try {
setDeletedFileIds((deletedFileIds) => {
selectedFiles.forEach((file) => deletedFileIds.add(file.id));
return new Set(deletedFileIds);
});
if (permanent) {
await deleteFromTrash(selectedFiles.map((file) => file.id));
} else {
await trashFiles(selectedFiles);
}
} catch (e) {
setDeletedFileIds(new Set());
throw e;
}
};
const hideFilesHelper = async (
selectedFiles: EnteFile[],
setHiddenFileIds: (
hiddenFileIds: Set<number> | ((prev: Set<number>) => Set<number>)
) => void
) => {
try {
// passing files here instead of filteredData because we want to move all files copies to hidden collection
setHiddenFileIds((hiddenFileIds) => {
selectedFiles.forEach((file) => hiddenFileIds.add(file.id));
return new Set(hiddenFileIds);
});
await moveToHiddenCollection(selectedFiles);
} catch (e) {
setHiddenFileIds(new Set());
throw e;
}
};
const fixTimeHelper = async (
selectedFiles: EnteFile[],
setFixCreationTimeAttributes: (fixCreationTimeAttributes: {
files: EnteFile[];
}) => void
) => {
setFixCreationTimeAttributes({ files: selectedFiles });
};