From 1d310babeeb2581d248a53cb8a3ab7d8a2b5c1b2 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Wed, 25 May 2022 15:35:48 +0530 Subject: [PATCH 001/295] init watch --- src/components/pages/gallery/Upload.tsx | 11 + src/services/upload/uploadManager.ts | 13 + src/services/watchService.ts | 319 ++++++++++++++++++++++++ 3 files changed, 343 insertions(+) create mode 100644 src/services/watchService.ts diff --git a/src/components/pages/gallery/Upload.tsx b/src/components/pages/gallery/Upload.tsx index cccaa955683de5e1046fd1b9aa120777c588ffa1..20841eac4ee83cbe75e927316172f3defda90d24 100644 --- a/src/components/pages/gallery/Upload.tsx +++ b/src/components/pages/gallery/Upload.tsx @@ -25,6 +25,7 @@ import UploadTypeSelector from '../../UploadTypeSelector'; import Router from 'next/router'; import { isCanvasBlocked } from 'utils/upload/isCanvasBlocked'; import { downloadApp } from 'utils/common'; +import watchService from 'services/watchService'; const FIRST_ALBUM_NAME = 'My First Album'; @@ -116,6 +117,12 @@ export default function Upload(props: Props) { resumeDesktopUpload(type, electronFiles, collectionName); } ); + watchService.setElectronFiles = props.setElectronFiles; + watchService.setCollectionName = (collectionName: string) => { + isPendingDesktopUpload.current = true; + pendingDesktopUploadCollectionName.current = collectionName; + }; + watchService.init(); } }, []); @@ -349,6 +356,10 @@ export default function Upload(props: Props) { filesWithCollectionToUpload, collections ); + await watchService.allUploadsDone( + filesWithCollectionToUpload, + collections + ); } catch (err) { const message = getUserFacingErrorMessage( err.message, diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index 8fbc6fd36882fac44ed0887bb47991a1a4b20821..802220ecef7f413d8b993b3feb759d43d03bf6c9 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -39,6 +39,7 @@ import uiService from './uiService'; import { logUploadInfo } from 'utils/upload'; import isElectron from 'is-electron'; import ImportService from 'services/importService'; +import watchService from 'services/watchService'; const MAX_CONCURRENT_UPLOADS = 4; const FILE_UPLOAD_COMPLETED = 100; @@ -399,6 +400,18 @@ class UploadManager { !areFileWithCollectionsSame(file, fileWithCollection) ); ImportService.updatePendingUploads(this.remainingFiles); + + if ( + fileUploadResult === FileUploadResults.UPLOADED || + fileUploadResult === + FileUploadResults.UPLOADED_WITH_STATIC_THUMBNAIL || + fileUploadResult === FileUploadResults.ALREADY_UPLOADED + ) { + await watchService.fileUploadDone( + fileWithCollection, + uploadedFile + ); + } } } catch (e) { logError(e, 'failed to do post file upload action'); diff --git a/src/services/watchService.ts b/src/services/watchService.ts new file mode 100644 index 0000000000000000000000000000000000000000..d9fe8b20b388c893ff309b073981e28b3bbcde55 --- /dev/null +++ b/src/services/watchService.ts @@ -0,0 +1,319 @@ +import { Collection } from 'types/collection'; +import { EnteFile } from 'types/file'; +import { ElectronFile, FileWithCollection } from 'types/upload'; +import { runningInBrowser } from 'utils/common'; +import { syncCollections } from './collectionService'; +import { syncFiles, trashFiles } from './fileService'; + +interface Mapping { + collectionName: string; + folderPath: string; + files: { + path: string; + id: number; + }[]; +} + +interface UploadQueueType { + collectionName: string; + paths: string[]; +} + +class WatchService { + ElectronAPIs: any; + allElectronAPIsExist: boolean = false; + uploadQueue: UploadQueueType[] = []; + isUploadRunning: boolean = false; + pathToIDMap = new Map(); + setElectronFiles: (files: ElectronFile[]) => void; + setCollectionName: (collectionName: string) => void; + + constructor() { + this.ElectronAPIs = runningInBrowser() && window['ElectronAPIs']; + this.allElectronAPIsExist = !!this.ElectronAPIs?.getWatchMappings; + } + + async init() { + if (this.allElectronAPIsExist) { + const mappings: Mapping[] = + await this.ElectronAPIs.getWatchMappings(); + + console.log('mappings', mappings); + + if (!mappings) { + return; + } + + for (const mapping of mappings) { + const filePathsOnDisk: string[] = + await this.ElectronAPIs.getFilePathsFromDir( + mapping.folderPath + ); + + const filesToUpload = filePathsOnDisk.filter((filePath) => { + return !mapping.files.find( + (file) => file.path === filePath + ); + }); + + const filesToRemove = mapping.files.filter((file) => { + return !filePathsOnDisk.find( + (filePath) => filePath === file.path + ); + }); + + if (filesToUpload.length > 0) { + const event: UploadQueueType = { + collectionName: mapping.collectionName, + paths: filesToUpload, + }; + this.uploadQueue.push(event); + } + + if (filesToRemove.length > 0) { + await this.trashByIDs( + filesToRemove, + mapping.collectionName + ); + mapping.files = mapping.files.filter( + (file) => + !filesToRemove.find( + (fileToRemove) => + file.path === fileToRemove.path + ) + ); + } + + this.runNextUpload(); + } + + this.ElectronAPIs.setWatchMappings(mappings); + this.setWatchFunctions(); + } + } + + async addWatchMapping(collectionName: string, folderPath: string) { + await this.ElectronAPIs.addWatchMapping(collectionName, folderPath); + } + + async removeWatchMapping(collectionName: string) { + await this.ElectronAPIs.removeWatchMapping(collectionName); + } + + async runNextUpload() { + if (this.uploadQueue.length === 0 || this.isUploadRunning) { + return; + } + + this.setCollectionName(this.uploadQueue[0].collectionName); + this.setElectronFiles( + await Promise.all( + this.uploadQueue[0].paths.map(async (path) => { + return await this.ElectronAPIs.getElectronFile(path); + }) + ) + ); + + this.isUploadRunning = true; + } + + async fileUploadDone( + fileWithCollection: FileWithCollection, + file: EnteFile + ) { + if (fileWithCollection.isLivePhoto) { + this.pathToIDMap.set( + (fileWithCollection.livePhotoAssets.image as ElectronFile).path, + file.id + ); + this.pathToIDMap.set( + (fileWithCollection.livePhotoAssets.video as ElectronFile).path, + file.id + ); + } else { + this.pathToIDMap.set( + (fileWithCollection.file as ElectronFile).path, + file.id + ); + } + } + + async allUploadsDone( + filesWithCollection: FileWithCollection[], + collections: Collection[] + ) { + if (this.allElectronAPIsExist) { + const collection = collections.find( + (collection) => + collection.id === filesWithCollection[0].collectionID + ); + if ( + !this.isUploadRunning || + this.uploadQueue.length === 0 || + this.uploadQueue[0].collectionName !== collection?.name + ) { + return; + } + + const uploadedFiles: Mapping['files'] = []; + for (const fileWithCollection of filesWithCollection) { + if (fileWithCollection.isLivePhoto) { + const imagePath = ( + fileWithCollection.livePhotoAssets.image as ElectronFile + ).path; + const videoPath = ( + fileWithCollection.livePhotoAssets.video as ElectronFile + ).path; + if ( + this.pathToIDMap.has(imagePath) && + this.pathToIDMap.has(videoPath) + ) { + uploadedFiles.push({ + path: imagePath, + id: this.pathToIDMap.get(imagePath), + }); + uploadedFiles.push({ + path: videoPath, + id: this.pathToIDMap.get(videoPath), + }); + + this.pathToIDMap.delete(imagePath); + this.pathToIDMap.delete(videoPath); + } + } else { + const filePath = (fileWithCollection.file as ElectronFile) + .path; + if (this.pathToIDMap.has(filePath)) { + uploadedFiles.push({ + path: filePath, + id: this.pathToIDMap.get(filePath), + }); + + this.pathToIDMap.delete(filePath); + } + } + } + + console.log('uploadedFiles', uploadedFiles); + + if (uploadedFiles.length > 0) { + const mappings: Mapping[] = + await this.ElectronAPIs.getWatchMappings(); + const mapping = mappings.find( + (mapping) => + mapping.collectionName === + this.uploadQueue[0].collectionName + ); + mapping.files = [...mapping.files, ...uploadedFiles]; + + console.log('new mappings', mappings); + + await this.ElectronAPIs.setWatchMappings(mappings); + + console.log( + 'now mappings', + await this.ElectronAPIs.getWatchMappings() + ); + } + + this.uploadQueue.shift(); + this.isUploadRunning = false; + this.runNextUpload(); + } + } + + setWatchFunctions() { + if (this.allElectronAPIsExist) { + this.ElectronAPIs.registerWatcherFunctions( + this, + diskFileAddedCallback, + diskFileRemovedCallback + ); + } + } + + async trashByIDs(toTrashFiles: Mapping['files'], collectionName: string) { + if (this.allElectronAPIsExist) { + const collections = await syncCollections(); + const collectionID = collections.find( + (collection) => collection.name === collectionName + )?.id; + if (!collectionID) { + return; + } + const files = await syncFiles(collections, () => {}); + + const idSet = new Set(); + for (const file of toTrashFiles) { + idSet.add(file.id); + } + + const filesToTrash = files.filter((file) => { + return idSet.has(file.id) && file.collectionID === collectionID; + }); + + await trashFiles(filesToTrash); + } + } + + async getCollectionName(filePath: string) { + const mappings: Mapping[] = await this.ElectronAPIs.getWatchMappings(); + + console.log('mappings', mappings, filePath); + + const collectionName = mappings.find((mapping) => + filePath.startsWith(mapping.folderPath) + )?.collectionName; + + if (!collectionName) { + return null; + } + + return collectionName; + } +} + +async function diskFileAddedCallback(w: WatchService, filePath: string) { + console.log('diskFileAddedCallback', w, filePath); + const collectionName = await w.getCollectionName(filePath); + + const event: UploadQueueType = { + collectionName, + paths: [filePath], + }; + w.uploadQueue.push(event); + w.runNextUpload(); +} + +async function diskFileRemovedCallback(w: WatchService, filePath: string) { + const collectionName = await w.getCollectionName(filePath); + + console.log('collection', collectionName); + + if (!collectionName) { + return; + } + + const mappings: Mapping[] = await w.ElectronAPIs.getWatchMappings(); + + const mapping = mappings.find( + (mapping) => mapping.collectionName === collectionName + ); + if (!mapping) { + return; + } + + const file = mapping.files.find((file) => file.path === filePath); + if (!file) { + return; + } + + await w.trashByIDs([file], collectionName); + + mapping.files = mapping.files.filter((file) => file.path !== filePath); + await w.ElectronAPIs.setWatchMappings(mappings); + + console.log('after trash', w.ElectronAPIs.getWatchMappings()); +} + +export default new WatchService(); From 440c5bf4f9b972119fae164e5006fe33cd7ba8ac Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Thu, 2 Jun 2022 18:48:43 +0530 Subject: [PATCH 002/295] return the file when upload is skipped since the file id is needed for watch service --- src/services/upload/uploader.ts | 16 +++++++++++++--- src/utils/upload/index.ts | 6 +++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/services/upload/uploader.ts b/src/services/upload/uploader.ts index b1cffab53181bd598759d7e81495b3cc6e769f30..166a6e454a5ff03df7e0868b56a6c40385383025 100644 --- a/src/services/upload/uploader.ts +++ b/src/services/upload/uploader.ts @@ -50,9 +50,16 @@ export default async function uploader( throw Error(CustomError.NO_METADATA); } - if (fileAlreadyInCollection(existingFilesInCollection, metadata)) { + const sameFileInSameCollection = fileAlreadyInCollection( + existingFilesInCollection, + metadata + ); + if (sameFileInSameCollection) { logUploadInfo(`skipped upload for ${fileNameSize}`); - return { fileUploadResult: FileUploadResults.ALREADY_UPLOADED }; + return { + fileUploadResult: FileUploadResults.ALREADY_UPLOADED, + uploadedFile: sameFileInSameCollection, + }; } const sameFileInOtherCollection = findSameFileInOtherCollection( @@ -82,7 +89,10 @@ export default async function uploader( fileAlreadyInCollection(existingFiles, metadata) ) { logUploadInfo(`deduped upload for ${fileNameSize}`); - return { fileUploadResult: FileUploadResults.ALREADY_UPLOADED }; + return { + fileUploadResult: FileUploadResults.ALREADY_UPLOADED, + uploadedFile: fileAlreadyInCollection(existingFiles, metadata), + }; } logUploadInfo(`reading asset ${fileNameSize}`); diff --git a/src/utils/upload/index.ts b/src/utils/upload/index.ts index cf8d8c228df02f0b3824f98fe5799aca53a78f24..12668484056b8df220ceca0bb9c14e2a794a102b 100644 --- a/src/utils/upload/index.ts +++ b/src/utils/upload/index.ts @@ -12,13 +12,13 @@ const DEDUPE_COLLECTION = new Set(['icloud library', 'icloudlibrary']); export function fileAlreadyInCollection( existingFilesInCollection: EnteFile[], newFileMetadata: Metadata -): boolean { +): EnteFile { for (const existingFile of existingFilesInCollection) { if (areFilesSame(existingFile.metadata, newFileMetadata)) { - return true; + return existingFile; } } - return false; + return null; } export function findSameFileInOtherCollection( From df5ecdf04665dc5e9a7c27f4c8e46a3c14da8972 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Thu, 2 Jun 2022 20:08:54 +0530 Subject: [PATCH 003/295] add watch modal --- src/components/WatchModal.tsx | 8 ++++ src/components/pages/gallery/Upload.tsx | 1 + src/services/watchService.ts | 52 ++++++++++++++----------- 3 files changed, 39 insertions(+), 22 deletions(-) create mode 100644 src/components/WatchModal.tsx diff --git a/src/components/WatchModal.tsx b/src/components/WatchModal.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1926da746b6b99993be73211ef8af5d2f9a95b1f --- /dev/null +++ b/src/components/WatchModal.tsx @@ -0,0 +1,8 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import React from 'react'; + +function WatchModal({ watchModalView, setWatchModalView }) { + return
WatchModal
; +} + +export default WatchModal; diff --git a/src/components/pages/gallery/Upload.tsx b/src/components/pages/gallery/Upload.tsx index 20841eac4ee83cbe75e927316172f3defda90d24..12c635d6e6296869fc3f57b1fd7f857955e785f9 100644 --- a/src/components/pages/gallery/Upload.tsx +++ b/src/components/pages/gallery/Upload.tsx @@ -122,6 +122,7 @@ export default function Upload(props: Props) { isPendingDesktopUpload.current = true; pendingDesktopUploadCollectionName.current = collectionName; }; + watchService.syncWithRemote = props.syncWithRemote; watchService.init(); } }, []); diff --git a/src/services/watchService.ts b/src/services/watchService.ts index d9fe8b20b388c893ff309b073981e28b3bbcde55..fda2ea4299a8096cad2decfe11c9ac1c4db834ea 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -27,6 +27,7 @@ class WatchService { pathToIDMap = new Map(); setElectronFiles: (files: ElectronFile[]) => void; setCollectionName: (collectionName: string) => void; + syncWithRemote: () => void; constructor() { this.ElectronAPIs = runningInBrowser() && window['ElectronAPIs']; @@ -89,6 +90,17 @@ class WatchService { this.ElectronAPIs.setWatchMappings(mappings); this.setWatchFunctions(); + this.syncWithRemote(); + } + } + + setWatchFunctions() { + if (this.allElectronAPIsExist) { + this.ElectronAPIs.registerWatcherFunctions( + this, + diskFileAddedCallback, + diskFileRemovedCallback + ); } } @@ -208,7 +220,8 @@ class WatchService { console.log('new mappings', mappings); - await this.ElectronAPIs.setWatchMappings(mappings); + this.ElectronAPIs.setWatchMappings(mappings); + this.syncWithRemote(); console.log( 'now mappings', @@ -222,16 +235,6 @@ class WatchService { } } - setWatchFunctions() { - if (this.allElectronAPIsExist) { - this.ElectronAPIs.registerWatcherFunctions( - this, - diskFileAddedCallback, - diskFileRemovedCallback - ); - } - } - async trashByIDs(toTrashFiles: Mapping['files'], collectionName: string) { if (this.allElectronAPIsExist) { const collections = await syncCollections(); @@ -273,20 +276,23 @@ class WatchService { } } -async function diskFileAddedCallback(w: WatchService, filePath: string) { - console.log('diskFileAddedCallback', w, filePath); - const collectionName = await w.getCollectionName(filePath); +async function diskFileAddedCallback(instance: WatchService, filePath: string) { + console.log('diskFileAddedCallback', instance, filePath); + const collectionName = await instance.getCollectionName(filePath); const event: UploadQueueType = { collectionName, paths: [filePath], }; - w.uploadQueue.push(event); - w.runNextUpload(); + instance.uploadQueue.push(event); + instance.runNextUpload(); } -async function diskFileRemovedCallback(w: WatchService, filePath: string) { - const collectionName = await w.getCollectionName(filePath); +async function diskFileRemovedCallback( + instance: WatchService, + filePath: string +) { + const collectionName = await instance.getCollectionName(filePath); console.log('collection', collectionName); @@ -294,7 +300,7 @@ async function diskFileRemovedCallback(w: WatchService, filePath: string) { return; } - const mappings: Mapping[] = await w.ElectronAPIs.getWatchMappings(); + let mappings: Mapping[] = await instance.ElectronAPIs.getWatchMappings(); const mapping = mappings.find( (mapping) => mapping.collectionName === collectionName @@ -308,12 +314,14 @@ async function diskFileRemovedCallback(w: WatchService, filePath: string) { return; } - await w.trashByIDs([file], collectionName); + await instance.trashByIDs([file], collectionName); + mappings = await instance.ElectronAPIs.getWatchMappings(); mapping.files = mapping.files.filter((file) => file.path !== filePath); - await w.ElectronAPIs.setWatchMappings(mappings); + instance.ElectronAPIs.setWatchMappings(mappings); + instance.syncWithRemote(); - console.log('after trash', w.ElectronAPIs.getWatchMappings()); + console.log('after trash', instance.ElectronAPIs.getWatchMappings()); } export default new WatchService(); From 5361dca3e211d8d1b71193cf47cc9196e8be5e04 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Fri, 3 Jun 2022 16:32:49 +0530 Subject: [PATCH 004/295] added debounce for uploads --- src/services/watchService.ts | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/services/watchService.ts b/src/services/watchService.ts index fda2ea4299a8096cad2decfe11c9ac1c4db834ea..a212bdbe2fc0b022d5ed97db726d66c0d74ed8c4 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -4,6 +4,7 @@ import { ElectronFile, FileWithCollection } from 'types/upload'; import { runningInBrowser } from 'utils/common'; import { syncCollections } from './collectionService'; import { syncFiles, trashFiles } from './fileService'; +import debounce from 'debounce-promise'; interface Mapping { collectionName: string; @@ -28,6 +29,7 @@ class WatchService { setElectronFiles: (files: ElectronFile[]) => void; setCollectionName: (collectionName: string) => void; syncWithRemote: () => void; + promise: Promise; constructor() { this.ElectronAPIs = runningInBrowser() && window['ElectronAPIs']; @@ -117,6 +119,23 @@ class WatchService { return; } + this.isUploadRunning = true; + + const newUploadQueue = [this.uploadQueue[0]]; + const len = this.uploadQueue.length; + for (let i = 1; i < len; i++) { + if ( + this.uploadQueue[i].collectionName === + newUploadQueue[0].collectionName + ) { + newUploadQueue[0].paths.push(...this.uploadQueue[i].paths); + } else { + newUploadQueue.push(this.uploadQueue[i]); + } + } + newUploadQueue.push(...this.uploadQueue.slice(len)); + this.uploadQueue = newUploadQueue; + this.setCollectionName(this.uploadQueue[0].collectionName); this.setElectronFiles( await Promise.all( @@ -125,8 +144,6 @@ class WatchService { }) ) ); - - this.isUploadRunning = true; } async fileUploadDone( @@ -285,7 +302,8 @@ async function diskFileAddedCallback(instance: WatchService, filePath: string) { paths: [filePath], }; instance.uploadQueue.push(event); - instance.runNextUpload(); + // instance.runNextUpload(); + await debounce(runNextUploadByInstance, 300)(instance); } async function diskFileRemovedCallback( @@ -324,4 +342,8 @@ async function diskFileRemovedCallback( console.log('after trash', instance.ElectronAPIs.getWatchMappings()); } +const runNextUploadByInstance = async (w: WatchService) => { + await w.runNextUpload(); +}; + export default new WatchService(); From c11e9d48784cda715a30e4530bc4a90ef551f496 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Sat, 4 Jun 2022 10:50:34 +0530 Subject: [PATCH 005/295] add watch modal and refactor --- src/components/WatchModal.tsx | 172 +++++++++++++++++++++++++++++++++- src/services/watchService.ts | 34 ++++--- 2 files changed, 192 insertions(+), 14 deletions(-) diff --git a/src/components/WatchModal.tsx b/src/components/WatchModal.tsx index 1926da746b6b99993be73211ef8af5d2f9a95b1f..6f6fba78a9ca33448c62cdf62b570fa9d8bf7091 100644 --- a/src/components/WatchModal.tsx +++ b/src/components/WatchModal.tsx @@ -1,8 +1,174 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import React from 'react'; +import React, { useEffect, useState } from 'react'; +import { Button, Modal } from 'react-bootstrap'; +import watchService, { WatchMapping } from 'services/watchService'; +import { MdDelete } from 'react-icons/md'; +import { HiArrowNarrowRight } from 'react-icons/hi'; function WatchModal({ watchModalView, setWatchModalView }) { - return
WatchModal
; + const [mappings, setMappings] = useState([]); + const [shouldUpdateMappings, setShouldUpdateMappings] = useState(true); + const [inputFolderPath, setInputFolderPath] = useState(''); + const [inputCollectionName, setInputCollectionName] = useState(''); + + useEffect(() => { + if (shouldUpdateMappings) { + setMappings(watchService.ElectronAPIs.getWatchMappings()); + setShouldUpdateMappings(false); + } + }, [shouldUpdateMappings]); + + const handleFolderSelection = async () => { + const folderPath = await watchService.selectFolder(); + setInputFolderPath(folderPath); + }; + + const handleCollectionNameChange = ( + e: React.ChangeEvent + ) => { + setInputCollectionName(e.target.value); + }; + + const handleAddWatchMapping = () => { + if (inputFolderPath.length > 0 && inputCollectionName.length > 0) { + watchService.addWatchMapping(inputCollectionName, inputFolderPath); + setInputCollectionName(''); + setInputFolderPath(''); + setShouldUpdateMappings(true); + } + }; + + const handleRemoveWatchMapping = (mapping: WatchMapping) => { + watchService.removeWatchMapping(mapping.collectionName); + setShouldUpdateMappings(true); + }; + + return ( + setWatchModalView(false)}> + + Watch Folders + + +
+ +
+ +
+ {inputFolderPath} +
+
+
+ +
+
+
+ Current Watch Mappings +
+
+ {mappings.map((mapping) => ( +
+
+ + {mapping.folderPath}{' '} + + + + {mapping.collectionName} + +
+
+ + handleRemoveWatchMapping(mapping) + } + /> +
+
+ ))} +
+
+
+ ); } export default WatchModal; diff --git a/src/services/watchService.ts b/src/services/watchService.ts index a212bdbe2fc0b022d5ed97db726d66c0d74ed8c4..936d140464b83e7c9123d46b3aa1bf4c15b98e60 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -6,7 +6,7 @@ import { syncCollections } from './collectionService'; import { syncFiles, trashFiles } from './fileService'; import debounce from 'debounce-promise'; -interface Mapping { +export interface WatchMapping { collectionName: string; folderPath: string; files: { @@ -38,8 +38,7 @@ class WatchService { async init() { if (this.allElectronAPIsExist) { - const mappings: Mapping[] = - await this.ElectronAPIs.getWatchMappings(); + const mappings = this.getWatchMappings(); console.log('mappings', mappings); @@ -49,7 +48,7 @@ class WatchService { for (const mapping of mappings) { const filePathsOnDisk: string[] = - await this.ElectronAPIs.getFilePathsFromDir( + await this.ElectronAPIs.getPosixFilePathsFromDir( mapping.folderPath ); @@ -114,6 +113,12 @@ class WatchService { await this.ElectronAPIs.removeWatchMapping(collectionName); } + getWatchMappings(): WatchMapping[] { + if (this.allElectronAPIsExist) { + return this.ElectronAPIs.getWatchMappings() ?? []; + } + } + async runNextUpload() { if (this.uploadQueue.length === 0 || this.isUploadRunning) { return; @@ -184,7 +189,7 @@ class WatchService { return; } - const uploadedFiles: Mapping['files'] = []; + const uploadedFiles: WatchMapping['files'] = []; for (const fileWithCollection of filesWithCollection) { if (fileWithCollection.isLivePhoto) { const imagePath = ( @@ -226,8 +231,7 @@ class WatchService { console.log('uploadedFiles', uploadedFiles); if (uploadedFiles.length > 0) { - const mappings: Mapping[] = - await this.ElectronAPIs.getWatchMappings(); + const mappings = this.getWatchMappings(); const mapping = mappings.find( (mapping) => mapping.collectionName === @@ -252,7 +256,10 @@ class WatchService { } } - async trashByIDs(toTrashFiles: Mapping['files'], collectionName: string) { + async trashByIDs( + toTrashFiles: WatchMapping['files'], + collectionName: string + ) { if (this.allElectronAPIsExist) { const collections = await syncCollections(); const collectionID = collections.find( @@ -277,7 +284,7 @@ class WatchService { } async getCollectionName(filePath: string) { - const mappings: Mapping[] = await this.ElectronAPIs.getWatchMappings(); + const mappings = this.getWatchMappings(); console.log('mappings', mappings, filePath); @@ -291,6 +298,11 @@ class WatchService { return collectionName; } + + async selectFolder(): Promise { + const folderPath = await this.ElectronAPIs.selectFolder(); + return folderPath; + } } async function diskFileAddedCallback(instance: WatchService, filePath: string) { @@ -318,7 +330,7 @@ async function diskFileRemovedCallback( return; } - let mappings: Mapping[] = await instance.ElectronAPIs.getWatchMappings(); + let mappings = instance.getWatchMappings(); const mapping = mappings.find( (mapping) => mapping.collectionName === collectionName @@ -334,7 +346,7 @@ async function diskFileRemovedCallback( await instance.trashByIDs([file], collectionName); - mappings = await instance.ElectronAPIs.getWatchMappings(); + mappings = instance.getWatchMappings(); mapping.files = mapping.files.filter((file) => file.path !== filePath); instance.ElectronAPIs.setWatchMappings(mappings); instance.syncWithRemote(); From e85c16accbd306ee40faa55e935b8f26566adf75 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Sat, 4 Jun 2022 11:04:50 +0530 Subject: [PATCH 006/295] fix functions --- src/components/WatchModal.tsx | 2 +- src/services/watchService.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/WatchModal.tsx b/src/components/WatchModal.tsx index 6f6fba78a9ca33448c62cdf62b570fa9d8bf7091..4e4219e9dc3d75ab6c60dd6b830923ceca28da67 100644 --- a/src/components/WatchModal.tsx +++ b/src/components/WatchModal.tsx @@ -12,7 +12,7 @@ function WatchModal({ watchModalView, setWatchModalView }) { useEffect(() => { if (shouldUpdateMappings) { - setMappings(watchService.ElectronAPIs.getWatchMappings()); + setMappings(watchService.getWatchMappings()); setShouldUpdateMappings(false); } }, [shouldUpdateMappings]); diff --git a/src/services/watchService.ts b/src/services/watchService.ts index 936d140464b83e7c9123d46b3aa1bf4c15b98e60..842f5223e9c63b3ec0d7c3760f8ecf7a52a3e1e5 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -105,12 +105,12 @@ class WatchService { } } - async addWatchMapping(collectionName: string, folderPath: string) { - await this.ElectronAPIs.addWatchMapping(collectionName, folderPath); + addWatchMapping(collectionName: string, folderPath: string) { + this.ElectronAPIs.addWatchMapping(collectionName, folderPath); } - async removeWatchMapping(collectionName: string) { - await this.ElectronAPIs.removeWatchMapping(collectionName); + removeWatchMapping(collectionName: string) { + this.ElectronAPIs.removeWatchMapping(collectionName); } getWatchMappings(): WatchMapping[] { From 02f6c353aad9b57cbad00b58407afd1aa9f05729 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Sat, 4 Jun 2022 12:40:14 +0530 Subject: [PATCH 007/295] remove from collection instead of trashing --- src/components/WatchModal.tsx | 11 +++++--- src/services/watchService.ts | 53 ++++++++++++++++++++--------------- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/components/WatchModal.tsx b/src/components/WatchModal.tsx index 4e4219e9dc3d75ab6c60dd6b830923ceca28da67..4ff4f9f1e808aa27cfbbd86e74f07ffbedf29b72 100644 --- a/src/components/WatchModal.tsx +++ b/src/components/WatchModal.tsx @@ -28,17 +28,20 @@ function WatchModal({ watchModalView, setWatchModalView }) { setInputCollectionName(e.target.value); }; - const handleAddWatchMapping = () => { + const handleAddWatchMapping = async () => { if (inputFolderPath.length > 0 && inputCollectionName.length > 0) { - watchService.addWatchMapping(inputCollectionName, inputFolderPath); + await watchService.addWatchMapping( + inputCollectionName, + inputFolderPath + ); setInputCollectionName(''); setInputFolderPath(''); setShouldUpdateMappings(true); } }; - const handleRemoveWatchMapping = (mapping: WatchMapping) => { - watchService.removeWatchMapping(mapping.collectionName); + const handleRemoveWatchMapping = async (mapping: WatchMapping) => { + await watchService.removeWatchMapping(mapping.collectionName); setShouldUpdateMappings(true); }; diff --git a/src/services/watchService.ts b/src/services/watchService.ts index 842f5223e9c63b3ec0d7c3760f8ecf7a52a3e1e5..9be3e11e2eece027d96d9be91d1924af32cdffa9 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -2,8 +2,8 @@ import { Collection } from 'types/collection'; import { EnteFile } from 'types/file'; import { ElectronFile, FileWithCollection } from 'types/upload'; import { runningInBrowser } from 'utils/common'; -import { syncCollections } from './collectionService'; -import { syncFiles, trashFiles } from './fileService'; +import { removeFromCollection, syncCollections } from './collectionService'; +import { syncFiles } from './fileService'; import debounce from 'debounce-promise'; export interface WatchMapping { @@ -29,7 +29,6 @@ class WatchService { setElectronFiles: (files: ElectronFile[]) => void; setCollectionName: (collectionName: string) => void; syncWithRemote: () => void; - promise: Promise; constructor() { this.ElectronAPIs = runningInBrowser() && window['ElectronAPIs']; @@ -105,12 +104,12 @@ class WatchService { } } - addWatchMapping(collectionName: string, folderPath: string) { - this.ElectronAPIs.addWatchMapping(collectionName, folderPath); + async addWatchMapping(collectionName: string, folderPath: string) { + await this.ElectronAPIs.addWatchMapping(collectionName, folderPath); } - removeWatchMapping(collectionName: string) { - this.ElectronAPIs.removeWatchMapping(collectionName); + async removeWatchMapping(collectionName: string) { + await this.ElectronAPIs.removeWatchMapping(collectionName); } getWatchMappings(): WatchMapping[] { @@ -190,6 +189,7 @@ class WatchService { } const uploadedFiles: WatchMapping['files'] = []; + for (const fileWithCollection of filesWithCollection) { if (fileWithCollection.isLivePhoto) { const imagePath = ( @@ -262,10 +262,10 @@ class WatchService { ) { if (this.allElectronAPIsExist) { const collections = await syncCollections(); - const collectionID = collections.find( + const collection = collections.find( (collection) => collection.name === collectionName - )?.id; - if (!collectionID) { + ); + if (!collection) { return; } const files = await syncFiles(collections, () => {}); @@ -276,10 +276,12 @@ class WatchService { } const filesToTrash = files.filter((file) => { - return idSet.has(file.id) && file.collectionID === collectionID; + return ( + idSet.has(file.id) && file.collectionID === collection.id + ); }); - await trashFiles(filesToTrash); + await removeFromCollection(collection, filesToTrash); } } @@ -306,15 +308,19 @@ class WatchService { } async function diskFileAddedCallback(instance: WatchService, filePath: string) { - console.log('diskFileAddedCallback', instance, filePath); const collectionName = await instance.getCollectionName(filePath); + if (!collectionName) { + return; + } + + console.log('adding', collectionName, filePath); + const event: UploadQueueType = { collectionName, paths: [filePath], }; instance.uploadQueue.push(event); - // instance.runNextUpload(); await debounce(runNextUploadByInstance, 300)(instance); } @@ -324,34 +330,37 @@ async function diskFileRemovedCallback( ) { const collectionName = await instance.getCollectionName(filePath); - console.log('collection', collectionName); + console.log('removing', collectionName, filePath); if (!collectionName) { return; } - let mappings = instance.getWatchMappings(); + const mappings = instance.getWatchMappings(); - const mapping = mappings.find( + const mappingIdx = mappings.findIndex( (mapping) => mapping.collectionName === collectionName ); - if (!mapping) { + if (mappingIdx === -1) { return; } - const file = mapping.files.find((file) => file.path === filePath); + const file = mappings[mappingIdx].files.find( + (file) => file.path === filePath + ); if (!file) { return; } await instance.trashByIDs([file], collectionName); - mappings = instance.getWatchMappings(); - mapping.files = mapping.files.filter((file) => file.path !== filePath); + mappings[mappingIdx].files = mappings[mappingIdx].files.filter( + (file) => file.path !== filePath + ); instance.ElectronAPIs.setWatchMappings(mappings); instance.syncWithRemote(); - console.log('after trash', instance.ElectronAPIs.getWatchMappings()); + console.log('after trash', instance.getWatchMappings()); } const runNextUploadByInstance = async (w: WatchService) => { From 54f914453e8a0aa0abb0d97875f98a2a1e699c56 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Sun, 5 Jun 2022 22:20:56 +0530 Subject: [PATCH 008/295] rename --- src/components/pages/gallery/Upload.tsx | 2 +- src/services/upload/uploadManager.ts | 2 +- src/services/watchService.ts | 9 ++------- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/components/pages/gallery/Upload.tsx b/src/components/pages/gallery/Upload.tsx index 12c635d6e6296869fc3f57b1fd7f857955e785f9..61fd7b96f4547cdb87546558e42e85d3fece7e17 100644 --- a/src/components/pages/gallery/Upload.tsx +++ b/src/components/pages/gallery/Upload.tsx @@ -357,7 +357,7 @@ export default function Upload(props: Props) { filesWithCollectionToUpload, collections ); - await watchService.allUploadsDone( + await watchService.allFileUploadsDone( filesWithCollectionToUpload, collections ); diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index 802220ecef7f413d8b993b3feb759d43d03bf6c9..e4c7c144fea811778da6257cc3af9f3c765acab6 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -407,7 +407,7 @@ class UploadManager { FileUploadResults.UPLOADED_WITH_STATIC_THUMBNAIL || fileUploadResult === FileUploadResults.ALREADY_UPLOADED ) { - await watchService.fileUploadDone( + await watchService.fileUploaded( fileWithCollection, uploadedFile ); diff --git a/src/services/watchService.ts b/src/services/watchService.ts index 9be3e11e2eece027d96d9be91d1924af32cdffa9..cf59fabb9f78ace5cca0d70466a6fc7bbc2684b6 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -150,10 +150,7 @@ class WatchService { ); } - async fileUploadDone( - fileWithCollection: FileWithCollection, - file: EnteFile - ) { + async fileUploaded(fileWithCollection: FileWithCollection, file: EnteFile) { if (fileWithCollection.isLivePhoto) { this.pathToIDMap.set( (fileWithCollection.livePhotoAssets.image as ElectronFile).path, @@ -171,7 +168,7 @@ class WatchService { } } - async allUploadsDone( + async allFileUploadsDone( filesWithCollection: FileWithCollection[], collections: Collection[] ) { @@ -239,8 +236,6 @@ class WatchService { ); mapping.files = [...mapping.files, ...uploadedFiles]; - console.log('new mappings', mappings); - this.ElectronAPIs.setWatchMappings(mappings); this.syncWithRemote(); From a0bcdc53292a71920308301c0644e1139f30bb88 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Sun, 5 Jun 2022 23:29:44 +0530 Subject: [PATCH 009/295] added trash type to event queue --- src/services/watchService.ts | 177 +++++++++++++++++++---------------- 1 file changed, 98 insertions(+), 79 deletions(-) diff --git a/src/services/watchService.ts b/src/services/watchService.ts index cf59fabb9f78ace5cca0d70466a6fc7bbc2684b6..11feb96ba62db62717c4d9062f6dd3912b509544 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -15,7 +15,8 @@ export interface WatchMapping { }[]; } -interface UploadQueueType { +interface EventQueueType { + type: 'upload' | 'trash'; collectionName: string; paths: string[]; } @@ -23,8 +24,8 @@ interface UploadQueueType { class WatchService { ElectronAPIs: any; allElectronAPIsExist: boolean = false; - uploadQueue: UploadQueueType[] = []; - isUploadRunning: boolean = false; + eventQueue: EventQueueType[] = []; + isEventRunning: boolean = false; pathToIDMap = new Map(); setElectronFiles: (files: ElectronFile[]) => void; setCollectionName: (collectionName: string) => void; @@ -64,33 +65,27 @@ class WatchService { }); if (filesToUpload.length > 0) { - const event: UploadQueueType = { + const event: EventQueueType = { + type: 'upload', collectionName: mapping.collectionName, paths: filesToUpload, }; - this.uploadQueue.push(event); + this.eventQueue.push(event); } if (filesToRemove.length > 0) { - await this.trashByIDs( - filesToRemove, - mapping.collectionName - ); - mapping.files = mapping.files.filter( - (file) => - !filesToRemove.find( - (fileToRemove) => - file.path === fileToRemove.path - ) - ); + const event: EventQueueType = { + type: 'trash', + collectionName: mapping.collectionName, + paths: filesToRemove.map((file) => file.path), + }; + this.eventQueue.push(event); } - - this.runNextUpload(); } - this.ElectronAPIs.setWatchMappings(mappings); this.setWatchFunctions(); this.syncWithRemote(); + await this.runNextEvent(); } } @@ -118,32 +113,47 @@ class WatchService { } } + async runNextEvent() { + console.log('runNextEvent mappings', this.getWatchMappings()); + + if (this.eventQueue.length === 0) { + return; + } + + if (this.eventQueue[0].type === 'upload') { + this.runNextUpload(); + } else { + this.runNextTrash(); + } + } + async runNextUpload() { - if (this.uploadQueue.length === 0 || this.isUploadRunning) { + if (this.eventQueue.length === 0 || this.isEventRunning) { return; } - this.isUploadRunning = true; + this.isEventRunning = true; - const newUploadQueue = [this.uploadQueue[0]]; - const len = this.uploadQueue.length; + const newUploadQueue = [this.eventQueue[0]]; + const len = this.eventQueue.length; for (let i = 1; i < len; i++) { if ( - this.uploadQueue[i].collectionName === - newUploadQueue[0].collectionName + this.eventQueue[i].collectionName === + newUploadQueue[0].collectionName && + this.eventQueue[i].type === newUploadQueue[0].type ) { - newUploadQueue[0].paths.push(...this.uploadQueue[i].paths); + newUploadQueue[0].paths.push(...this.eventQueue[i].paths); } else { - newUploadQueue.push(this.uploadQueue[i]); + newUploadQueue.push(this.eventQueue[i]); } } - newUploadQueue.push(...this.uploadQueue.slice(len)); - this.uploadQueue = newUploadQueue; + newUploadQueue.push(...this.eventQueue.slice(len)); + this.eventQueue = newUploadQueue; - this.setCollectionName(this.uploadQueue[0].collectionName); + this.setCollectionName(this.eventQueue[0].collectionName); this.setElectronFiles( await Promise.all( - this.uploadQueue[0].paths.map(async (path) => { + this.eventQueue[0].paths.map(async (path) => { return await this.ElectronAPIs.getElectronFile(path); }) ) @@ -178,9 +188,9 @@ class WatchService { collection.id === filesWithCollection[0].collectionID ); if ( - !this.isUploadRunning || - this.uploadQueue.length === 0 || - this.uploadQueue[0].collectionName !== collection?.name + !this.isEventRunning || + this.eventQueue.length === 0 || + this.eventQueue[0].collectionName !== collection?.name ) { return; } @@ -225,30 +235,58 @@ class WatchService { } } - console.log('uploadedFiles', uploadedFiles); - if (uploadedFiles.length > 0) { const mappings = this.getWatchMappings(); const mapping = mappings.find( (mapping) => mapping.collectionName === - this.uploadQueue[0].collectionName + this.eventQueue[0].collectionName ); mapping.files = [...mapping.files, ...uploadedFiles]; this.ElectronAPIs.setWatchMappings(mappings); this.syncWithRemote(); - - console.log( - 'now mappings', - await this.ElectronAPIs.getWatchMappings() - ); } - this.uploadQueue.shift(); - this.isUploadRunning = false; - this.runNextUpload(); + this.eventQueue.shift(); + this.isEventRunning = false; + this.runNextEvent(); + } + } + + async runNextTrash() { + if (this.eventQueue.length === 0 || this.isEventRunning) { + return; + } + + this.isEventRunning = true; + + const { collectionName, paths } = this.eventQueue[0]; + const filePathsToRemove = new Set(paths); + + const mappings = this.getWatchMappings(); + const mappingIdx = mappings.findIndex( + (mapping) => mapping.collectionName === collectionName + ); + if (mappingIdx === -1) { + return; } + + const files = mappings[mappingIdx].files.filter((file) => + filePathsToRemove.has(file.path) + ); + + await this.trashByIDs(files, collectionName); + + mappings[mappingIdx].files = mappings[mappingIdx].files.filter( + (file) => !filePathsToRemove.has(file.path) + ); + this.ElectronAPIs.setWatchMappings(mappings); + this.syncWithRemote(); + + this.eventQueue.shift(); + this.isEventRunning = false; + this.runNextEvent(); } async trashByIDs( @@ -283,8 +321,6 @@ class WatchService { async getCollectionName(filePath: string) { const mappings = this.getWatchMappings(); - console.log('mappings', mappings, filePath); - const collectionName = mappings.find((mapping) => filePath.startsWith(mapping.folderPath) )?.collectionName; @@ -309,14 +345,15 @@ async function diskFileAddedCallback(instance: WatchService, filePath: string) { return; } - console.log('adding', collectionName, filePath); + console.log('added (upload) to event queue', collectionName, filePath); - const event: UploadQueueType = { + const event: EventQueueType = { + type: 'upload', collectionName, paths: [filePath], }; - instance.uploadQueue.push(event); - await debounce(runNextUploadByInstance, 300)(instance); + instance.eventQueue.push(event); + await debounce(runNextEventByInstance, 300)(instance); } async function diskFileRemovedCallback( @@ -325,41 +362,23 @@ async function diskFileRemovedCallback( ) { const collectionName = await instance.getCollectionName(filePath); - console.log('removing', collectionName, filePath); + console.log('added (trash) to event queue', collectionName, filePath); if (!collectionName) { return; } - const mappings = instance.getWatchMappings(); - - const mappingIdx = mappings.findIndex( - (mapping) => mapping.collectionName === collectionName - ); - if (mappingIdx === -1) { - return; - } - - const file = mappings[mappingIdx].files.find( - (file) => file.path === filePath - ); - if (!file) { - return; - } - - await instance.trashByIDs([file], collectionName); - - mappings[mappingIdx].files = mappings[mappingIdx].files.filter( - (file) => file.path !== filePath - ); - instance.ElectronAPIs.setWatchMappings(mappings); - instance.syncWithRemote(); - - console.log('after trash', instance.getWatchMappings()); + const event: EventQueueType = { + type: 'trash', + collectionName, + paths: [filePath], + }; + instance.eventQueue.push(event); + await debounce(runNextEventByInstance, 300)(instance); } -const runNextUploadByInstance = async (w: WatchService) => { - await w.runNextUpload(); +const runNextEventByInstance = async (w: WatchService) => { + await w.runNextEvent(); }; export default new WatchService(); From 71b9555fa634d3b4941c165efd1776978a7e2e43 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Mon, 6 Jun 2022 10:35:04 +0530 Subject: [PATCH 010/295] batch events whenever possible --- src/services/watchService.ts | 37 +++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/services/watchService.ts b/src/services/watchService.ts index 11feb96ba62db62717c4d9062f6dd3912b509544..5f12f1f7d7d4a81a35b9e7d68aa2eafbc5abd243 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -134,21 +134,7 @@ class WatchService { this.isEventRunning = true; - const newUploadQueue = [this.eventQueue[0]]; - const len = this.eventQueue.length; - for (let i = 1; i < len; i++) { - if ( - this.eventQueue[i].collectionName === - newUploadQueue[0].collectionName && - this.eventQueue[i].type === newUploadQueue[0].type - ) { - newUploadQueue[0].paths.push(...this.eventQueue[i].paths); - } else { - newUploadQueue.push(this.eventQueue[i]); - } - } - newUploadQueue.push(...this.eventQueue.slice(len)); - this.eventQueue = newUploadQueue; + this.batchNextEvent(); this.setCollectionName(this.eventQueue[0].collectionName); this.setElectronFiles( @@ -261,6 +247,8 @@ class WatchService { this.isEventRunning = true; + this.batchNextEvent(); + const { collectionName, paths } = this.eventQueue[0]; const filePathsToRemove = new Set(paths); @@ -336,6 +324,25 @@ class WatchService { const folderPath = await this.ElectronAPIs.selectFolder(); return folderPath; } + + // Batches all the files to be uploaded (or trashed) of same collection as the next event + batchNextEvent() { + const newEventQueue = [this.eventQueue[0]]; + const len = this.eventQueue.length; + for (let i = 1; i < len; i++) { + if ( + this.eventQueue[i].collectionName === + newEventQueue[0].collectionName && + this.eventQueue[i].type === newEventQueue[0].type + ) { + newEventQueue[0].paths.push(...this.eventQueue[i].paths); + } else { + newEventQueue.push(this.eventQueue[i]); + } + } + newEventQueue.push(...this.eventQueue.slice(len)); + this.eventQueue = newEventQueue; + } } async function diskFileAddedCallback(instance: WatchService, filePath: string) { From 2bd43cdabf28d6939ac33aff71c7ab1bac422ffe Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Mon, 6 Jun 2022 10:56:51 +0530 Subject: [PATCH 011/295] refactor --- src/components/pages/gallery/Upload.tsx | 26 +++++++++++++--------- src/services/watchService.ts | 29 +++++++++++++++++++------ 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/components/pages/gallery/Upload.tsx b/src/components/pages/gallery/Upload.tsx index 61fd7b96f4547cdb87546558e42e85d3fece7e17..1ea393be4e619957d840c0b1fd7060678db54ede 100644 --- a/src/components/pages/gallery/Upload.tsx +++ b/src/components/pages/gallery/Upload.tsx @@ -117,16 +117,20 @@ export default function Upload(props: Props) { resumeDesktopUpload(type, electronFiles, collectionName); } ); - watchService.setElectronFiles = props.setElectronFiles; - watchService.setCollectionName = (collectionName: string) => { - isPendingDesktopUpload.current = true; - pendingDesktopUploadCollectionName.current = collectionName; - }; - watchService.syncWithRemote = props.syncWithRemote; + watchService.setWatchServiceFunctions( + props.setElectronFiles, + setCollectionName, + props.syncWithRemote + ); watchService.init(); } }, []); + const setCollectionName = (collectionName: string) => { + isPendingDesktopUpload.current = true; + pendingDesktopUploadCollectionName.current = collectionName; + }; + useEffect(() => { if ( props.electronFiles?.length > 0 || @@ -357,10 +361,6 @@ export default function Upload(props: Props) { filesWithCollectionToUpload, collections ); - await watchService.allFileUploadsDone( - filesWithCollectionToUpload, - collections - ); } catch (err) { const message = getUserFacingErrorMessage( err.message, @@ -372,6 +372,12 @@ export default function Upload(props: Props) { } finally { props.setUploadInProgress(false); props.syncWithRemote(); + if (isElectron()) { + await watchService.allFileUploadsDone( + filesWithCollectionToUpload, + collections + ); + } } }; const retryFailed = async () => { diff --git a/src/services/watchService.ts b/src/services/watchService.ts index 5f12f1f7d7d4a81a35b9e7d68aa2eafbc5abd243..b92978634455f5abe23eb15794363b1238112bf5 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -36,6 +36,16 @@ class WatchService { this.allElectronAPIsExist = !!this.ElectronAPIs?.getWatchMappings; } + setWatchServiceFunctions( + setElectronFiles: (files: ElectronFile[]) => void, + setCollectionName: (collectionName: string) => void, + syncWithRemote: () => void + ) { + this.setElectronFiles = setElectronFiles; + this.setCollectionName = setCollectionName; + this.syncWithRemote = syncWithRemote; + } + async init() { if (this.allElectronAPIsExist) { const mappings = this.getWatchMappings(); @@ -100,23 +110,28 @@ class WatchService { } async addWatchMapping(collectionName: string, folderPath: string) { - await this.ElectronAPIs.addWatchMapping(collectionName, folderPath); + if (this.allElectronAPIsExist) { + await this.ElectronAPIs.addWatchMapping(collectionName, folderPath); + } } async removeWatchMapping(collectionName: string) { - await this.ElectronAPIs.removeWatchMapping(collectionName); + if (this.allElectronAPIsExist) { + await this.ElectronAPIs.removeWatchMapping(collectionName); + } } getWatchMappings(): WatchMapping[] { if (this.allElectronAPIsExist) { return this.ElectronAPIs.getWatchMappings() ?? []; } + return []; } async runNextEvent() { console.log('runNextEvent mappings', this.getWatchMappings()); - if (this.eventQueue.length === 0) { + if (this.eventQueue.length === 0 || this.isEventRunning) { return; } @@ -127,7 +142,7 @@ class WatchService { } } - async runNextUpload() { + private async runNextUpload() { if (this.eventQueue.length === 0 || this.isEventRunning) { return; } @@ -240,7 +255,7 @@ class WatchService { } } - async runNextTrash() { + private async runNextTrash() { if (this.eventQueue.length === 0 || this.isEventRunning) { return; } @@ -277,7 +292,7 @@ class WatchService { this.runNextEvent(); } - async trashByIDs( + private async trashByIDs( toTrashFiles: WatchMapping['files'], collectionName: string ) { @@ -326,7 +341,7 @@ class WatchService { } // Batches all the files to be uploaded (or trashed) of same collection as the next event - batchNextEvent() { + private batchNextEvent() { const newEventQueue = [this.eventQueue[0]]; const len = this.eventQueue.length; for (let i = 1; i < len; i++) { From f1532a7aa1f361a9ddf0c802afe6d434127f1a79 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Mon, 6 Jun 2022 11:09:24 +0530 Subject: [PATCH 012/295] refactor: added error logging --- src/services/watchService.ts | 421 ++++++++++++++++++++--------------- 1 file changed, 239 insertions(+), 182 deletions(-) diff --git a/src/services/watchService.ts b/src/services/watchService.ts index b92978634455f5abe23eb15794363b1238112bf5..9928e891ca65c967b517042bcad4e4a608c832b0 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -5,6 +5,7 @@ import { runningInBrowser } from 'utils/common'; import { removeFromCollection, syncCollections } from './collectionService'; import { syncFiles } from './fileService'; import debounce from 'debounce-promise'; +import { logError } from 'utils/sentry'; export interface WatchMapping { collectionName: string; @@ -48,54 +49,58 @@ class WatchService { async init() { if (this.allElectronAPIsExist) { - const mappings = this.getWatchMappings(); - - console.log('mappings', mappings); + try { + const mappings = this.getWatchMappings(); - if (!mappings) { - return; - } + console.log('mappings', mappings); - for (const mapping of mappings) { - const filePathsOnDisk: string[] = - await this.ElectronAPIs.getPosixFilePathsFromDir( - mapping.folderPath - ); + if (!mappings) { + return; + } - const filesToUpload = filePathsOnDisk.filter((filePath) => { - return !mapping.files.find( - (file) => file.path === filePath - ); - }); + for (const mapping of mappings) { + const filePathsOnDisk: string[] = + await this.ElectronAPIs.getPosixFilePathsFromDir( + mapping.folderPath + ); + + const filesToUpload = filePathsOnDisk.filter((filePath) => { + return !mapping.files.find( + (file) => file.path === filePath + ); + }); + + const filesToRemove = mapping.files.filter((file) => { + return !filePathsOnDisk.find( + (filePath) => filePath === file.path + ); + }); + + if (filesToUpload.length > 0) { + const event: EventQueueType = { + type: 'upload', + collectionName: mapping.collectionName, + paths: filesToUpload, + }; + this.eventQueue.push(event); + } - const filesToRemove = mapping.files.filter((file) => { - return !filePathsOnDisk.find( - (filePath) => filePath === file.path - ); - }); - - if (filesToUpload.length > 0) { - const event: EventQueueType = { - type: 'upload', - collectionName: mapping.collectionName, - paths: filesToUpload, - }; - this.eventQueue.push(event); + if (filesToRemove.length > 0) { + const event: EventQueueType = { + type: 'trash', + collectionName: mapping.collectionName, + paths: filesToRemove.map((file) => file.path), + }; + this.eventQueue.push(event); + } } - if (filesToRemove.length > 0) { - const event: EventQueueType = { - type: 'trash', - collectionName: mapping.collectionName, - paths: filesToRemove.map((file) => file.path), - }; - this.eventQueue.push(event); - } + this.setWatchFunctions(); + this.syncWithRemote(); + await this.runNextEvent(); + } catch (e) { + logError(e, 'error while initializing watch service'); } - - this.setWatchFunctions(); - this.syncWithRemote(); - await this.runNextEvent(); } } @@ -111,19 +116,35 @@ class WatchService { async addWatchMapping(collectionName: string, folderPath: string) { if (this.allElectronAPIsExist) { - await this.ElectronAPIs.addWatchMapping(collectionName, folderPath); + try { + await this.ElectronAPIs.addWatchMapping( + collectionName, + folderPath + ); + } catch (e) { + logError(e, 'error while adding watch mapping'); + } } } async removeWatchMapping(collectionName: string) { if (this.allElectronAPIsExist) { - await this.ElectronAPIs.removeWatchMapping(collectionName); + try { + await this.ElectronAPIs.removeWatchMapping(collectionName); + } catch (e) { + logError(e, 'error while removing watch mapping'); + } } } getWatchMappings(): WatchMapping[] { if (this.allElectronAPIsExist) { - return this.ElectronAPIs.getWatchMappings() ?? []; + try { + return this.ElectronAPIs.getWatchMappings() ?? []; + } catch (e) { + logError(e, 'error while getting watch mappings'); + return []; + } } return []; } @@ -143,22 +164,26 @@ class WatchService { } private async runNextUpload() { - if (this.eventQueue.length === 0 || this.isEventRunning) { - return; - } + try { + if (this.eventQueue.length === 0 || this.isEventRunning) { + return; + } - this.isEventRunning = true; + this.isEventRunning = true; - this.batchNextEvent(); + this.batchNextEvent(); - this.setCollectionName(this.eventQueue[0].collectionName); - this.setElectronFiles( - await Promise.all( - this.eventQueue[0].paths.map(async (path) => { - return await this.ElectronAPIs.getElectronFile(path); - }) - ) - ); + this.setCollectionName(this.eventQueue[0].collectionName); + this.setElectronFiles( + await Promise.all( + this.eventQueue[0].paths.map(async (path) => { + return await this.ElectronAPIs.getElectronFile(path); + }) + ) + ); + } catch (e) { + logError(e, 'error while running next upload'); + } } async fileUploaded(fileWithCollection: FileWithCollection, file: EnteFile) { @@ -184,119 +209,132 @@ class WatchService { collections: Collection[] ) { if (this.allElectronAPIsExist) { - const collection = collections.find( - (collection) => - collection.id === filesWithCollection[0].collectionID - ); - if ( - !this.isEventRunning || - this.eventQueue.length === 0 || - this.eventQueue[0].collectionName !== collection?.name - ) { - return; - } + try { + const collection = collections.find( + (collection) => + collection.id === filesWithCollection[0].collectionID + ); + if ( + !this.isEventRunning || + this.eventQueue.length === 0 || + this.eventQueue[0].collectionName !== collection?.name + ) { + return; + } - const uploadedFiles: WatchMapping['files'] = []; - - for (const fileWithCollection of filesWithCollection) { - if (fileWithCollection.isLivePhoto) { - const imagePath = ( - fileWithCollection.livePhotoAssets.image as ElectronFile - ).path; - const videoPath = ( - fileWithCollection.livePhotoAssets.video as ElectronFile - ).path; - if ( - this.pathToIDMap.has(imagePath) && - this.pathToIDMap.has(videoPath) - ) { - uploadedFiles.push({ - path: imagePath, - id: this.pathToIDMap.get(imagePath), - }); - uploadedFiles.push({ - path: videoPath, - id: this.pathToIDMap.get(videoPath), - }); - - this.pathToIDMap.delete(imagePath); - this.pathToIDMap.delete(videoPath); - } - } else { - const filePath = (fileWithCollection.file as ElectronFile) - .path; - if (this.pathToIDMap.has(filePath)) { - uploadedFiles.push({ - path: filePath, - id: this.pathToIDMap.get(filePath), - }); - - this.pathToIDMap.delete(filePath); + const uploadedFiles: WatchMapping['files'] = []; + + for (const fileWithCollection of filesWithCollection) { + if (fileWithCollection.isLivePhoto) { + const imagePath = ( + fileWithCollection.livePhotoAssets + .image as ElectronFile + ).path; + const videoPath = ( + fileWithCollection.livePhotoAssets + .video as ElectronFile + ).path; + + if ( + this.pathToIDMap.has(imagePath) && + this.pathToIDMap.has(videoPath) + ) { + uploadedFiles.push({ + path: imagePath, + id: this.pathToIDMap.get(imagePath), + }); + uploadedFiles.push({ + path: videoPath, + id: this.pathToIDMap.get(videoPath), + }); + + this.pathToIDMap.delete(imagePath); + this.pathToIDMap.delete(videoPath); + } + } else { + const filePath = ( + fileWithCollection.file as ElectronFile + ).path; + + if (this.pathToIDMap.has(filePath)) { + uploadedFiles.push({ + path: filePath, + id: this.pathToIDMap.get(filePath), + }); + + this.pathToIDMap.delete(filePath); + } } } - } - if (uploadedFiles.length > 0) { - const mappings = this.getWatchMappings(); - const mapping = mappings.find( - (mapping) => - mapping.collectionName === - this.eventQueue[0].collectionName - ); - mapping.files = [...mapping.files, ...uploadedFiles]; + if (uploadedFiles.length > 0) { + const mappings = this.getWatchMappings(); + const mapping = mappings.find( + (mapping) => + mapping.collectionName === + this.eventQueue[0].collectionName + ); + mapping.files = [...mapping.files, ...uploadedFiles]; - this.ElectronAPIs.setWatchMappings(mappings); - this.syncWithRemote(); - } + this.ElectronAPIs.setWatchMappings(mappings); + this.syncWithRemote(); + } - this.eventQueue.shift(); - this.isEventRunning = false; - this.runNextEvent(); + this.eventQueue.shift(); + this.isEventRunning = false; + this.runNextEvent(); + } catch (e) { + logError(e, 'error while running all file uploads done'); + } } } private async runNextTrash() { - if (this.eventQueue.length === 0 || this.isEventRunning) { - return; - } + try { + if (this.eventQueue.length === 0 || this.isEventRunning) { + return; + } - this.isEventRunning = true; + this.isEventRunning = true; - this.batchNextEvent(); + this.batchNextEvent(); - const { collectionName, paths } = this.eventQueue[0]; - const filePathsToRemove = new Set(paths); + const { collectionName, paths } = this.eventQueue[0]; + const filePathsToRemove = new Set(paths); - const mappings = this.getWatchMappings(); - const mappingIdx = mappings.findIndex( - (mapping) => mapping.collectionName === collectionName - ); - if (mappingIdx === -1) { - return; - } + const mappings = this.getWatchMappings(); + const mappingIdx = mappings.findIndex( + (mapping) => mapping.collectionName === collectionName + ); + if (mappingIdx === -1) { + return; + } - const files = mappings[mappingIdx].files.filter((file) => - filePathsToRemove.has(file.path) - ); + const files = mappings[mappingIdx].files.filter((file) => + filePathsToRemove.has(file.path) + ); - await this.trashByIDs(files, collectionName); + await this.trashByIDs(files, collectionName); - mappings[mappingIdx].files = mappings[mappingIdx].files.filter( - (file) => !filePathsToRemove.has(file.path) - ); - this.ElectronAPIs.setWatchMappings(mappings); - this.syncWithRemote(); + mappings[mappingIdx].files = mappings[mappingIdx].files.filter( + (file) => !filePathsToRemove.has(file.path) + ); + this.ElectronAPIs.setWatchMappings(mappings); + this.syncWithRemote(); - this.eventQueue.shift(); - this.isEventRunning = false; - this.runNextEvent(); + this.eventQueue.shift(); + this.isEventRunning = false; + this.runNextEvent(); + } catch (e) { + logError(e, 'error while running next trash'); + } } private async trashByIDs( toTrashFiles: WatchMapping['files'], collectionName: string ) { - if (this.allElectronAPIsExist) { + try { const collections = await syncCollections(); const collection = collections.find( (collection) => collection.name === collectionName @@ -318,29 +356,40 @@ class WatchService { }); await removeFromCollection(collection, filesToTrash); + } catch (e) { + logError(e, 'error while trashing by IDs'); } } async getCollectionName(filePath: string) { - const mappings = this.getWatchMappings(); + try { + const mappings = this.getWatchMappings(); - const collectionName = mappings.find((mapping) => - filePath.startsWith(mapping.folderPath) - )?.collectionName; + const collectionName = mappings.find((mapping) => + filePath.startsWith(mapping.folderPath) + )?.collectionName; - if (!collectionName) { - return null; - } + if (!collectionName) { + return null; + } - return collectionName; + return collectionName; + } catch (e) { + logError(e, 'error while getting collection name'); + } } async selectFolder(): Promise { - const folderPath = await this.ElectronAPIs.selectFolder(); - return folderPath; + try { + const folderPath = await this.ElectronAPIs.selectFolder(); + return folderPath; + } catch (e) { + logError(e, 'error while selecting folder'); + } } - // Batches all the files to be uploaded (or trashed) of same collection as the next event + // Batches all the files to be uploaded (or trashed) from the + // event queue of same collection as the next event private batchNextEvent() { const newEventQueue = [this.eventQueue[0]]; const len = this.eventQueue.length; @@ -361,42 +410,50 @@ class WatchService { } async function diskFileAddedCallback(instance: WatchService, filePath: string) { - const collectionName = await instance.getCollectionName(filePath); - - if (!collectionName) { - return; - } + try { + const collectionName = await instance.getCollectionName(filePath); - console.log('added (upload) to event queue', collectionName, filePath); + if (!collectionName) { + return; + } - const event: EventQueueType = { - type: 'upload', - collectionName, - paths: [filePath], - }; - instance.eventQueue.push(event); - await debounce(runNextEventByInstance, 300)(instance); + console.log('added (upload) to event queue', collectionName, filePath); + + const event: EventQueueType = { + type: 'upload', + collectionName, + paths: [filePath], + }; + instance.eventQueue.push(event); + await debounce(runNextEventByInstance, 300)(instance); + } catch (e) { + logError(e, 'error while calling diskFileAddedCallback'); + } } async function diskFileRemovedCallback( instance: WatchService, filePath: string ) { - const collectionName = await instance.getCollectionName(filePath); + try { + const collectionName = await instance.getCollectionName(filePath); - console.log('added (trash) to event queue', collectionName, filePath); + console.log('added (trash) to event queue', collectionName, filePath); - if (!collectionName) { - return; - } + if (!collectionName) { + return; + } - const event: EventQueueType = { - type: 'trash', - collectionName, - paths: [filePath], - }; - instance.eventQueue.push(event); - await debounce(runNextEventByInstance, 300)(instance); + const event: EventQueueType = { + type: 'trash', + collectionName, + paths: [filePath], + }; + instance.eventQueue.push(event); + await debounce(runNextEventByInstance, 300)(instance); + } catch (e) { + logError(e, 'error while calling diskFileRemovedCallback'); + } } const runNextEventByInstance = async (w: WatchService) => { From 6a0ca2b69552e1c8fb2e124bf254492235db96a0 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Mon, 6 Jun 2022 15:20:45 +0530 Subject: [PATCH 013/295] add modal to sidebar --- src/components/Sidebar/UtilitySection.tsx | 11 +++++++++++ src/components/{ => Sidebar}/WatchModal.tsx | 0 src/utils/strings/englishConstants.tsx | 1 + 3 files changed, 12 insertions(+) rename src/components/{ => Sidebar}/WatchModal.tsx (100%) diff --git a/src/components/Sidebar/UtilitySection.tsx b/src/components/Sidebar/UtilitySection.tsx index 55618f3d57bc34a0307bb2a9ff22d2b6e51d1caa..1cddddc199e734477545cc45470b048ab993c753 100644 --- a/src/components/Sidebar/UtilitySection.tsx +++ b/src/components/Sidebar/UtilitySection.tsx @@ -7,6 +7,7 @@ import TwoFactorModal from 'components/TwoFactor/Modal'; import { PAGES } from 'constants/pages'; import { useRouter } from 'next/router'; import { AppContext } from 'pages/_app'; +import WatchModal from './WatchModal'; export default function UtilitySection({ closeSidebar }) { const router = useRouter(); @@ -14,6 +15,7 @@ export default function UtilitySection({ closeSidebar }) { const [recoverModalView, setRecoveryModalView] = useState(false); const [twoFactorModalView, setTwoFactorModalView] = useState(false); + const [watchModalView, setWatchModalView] = useState(false); // const [fixLargeThumbsView, setFixLargeThumbsView] = useState(false); const openRecoveryKeyModal = () => setRecoveryModalView(true); @@ -22,6 +24,8 @@ export default function UtilitySection({ closeSidebar }) { const openTwoFactorModalView = () => setTwoFactorModalView(true); const closeTwoFactorModalView = () => setTwoFactorModalView(false); + const openWatchModalView = () => setWatchModalView(true); + const redirectToChangePasswordPage = () => { closeSidebar(); router.push(PAGES.CHANGE_PASSWORD); @@ -60,6 +64,9 @@ export default function UtilitySection({ closeSidebar }) { {constants.DEDUPLICATE_FILES} + + {constants.WATCH_FOLDERS} + {/* {constants.COMPRESS_THUMBNAILS} @@ -76,6 +83,10 @@ export default function UtilitySection({ closeSidebar }) { closeSidebar={closeSidebar} setLoading={startLoading} /> + {/* ), + WATCH_FOLDERS: 'Watch Folders', }; export default englishConstants; From 44033eb4fd51939c14e034fedd27c4b7272cd101 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Tue, 7 Jun 2022 11:11:14 +0530 Subject: [PATCH 014/295] convert modal to mui --- src/components/Sidebar/WatchModal.tsx | 78 +++++++++++++-------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/src/components/Sidebar/WatchModal.tsx b/src/components/Sidebar/WatchModal.tsx index 4ff4f9f1e808aa27cfbbd86e74f07ffbedf29b72..dca115aa48590339b57e4ad230363048056d4025 100644 --- a/src/components/Sidebar/WatchModal.tsx +++ b/src/components/Sidebar/WatchModal.tsx @@ -1,14 +1,15 @@ import React, { useEffect, useState } from 'react'; -import { Button, Modal } from 'react-bootstrap'; +import { Button, Dialog, IconButton } from '@mui/material'; import watchService, { WatchMapping } from 'services/watchService'; import { MdDelete } from 'react-icons/md'; -import { HiArrowNarrowRight } from 'react-icons/hi'; +import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; +import Close from '@mui/icons-material/Close'; +import { SpaceBetweenFlex } from 'components/Container'; function WatchModal({ watchModalView, setWatchModalView }) { const [mappings, setMappings] = useState([]); const [shouldUpdateMappings, setShouldUpdateMappings] = useState(true); const [inputFolderPath, setInputFolderPath] = useState(''); - const [inputCollectionName, setInputCollectionName] = useState(''); useEffect(() => { if (shouldUpdateMappings) { @@ -22,19 +23,12 @@ function WatchModal({ watchModalView, setWatchModalView }) { setInputFolderPath(folderPath); }; - const handleCollectionNameChange = ( - e: React.ChangeEvent - ) => { - setInputCollectionName(e.target.value); - }; - const handleAddWatchMapping = async () => { - if (inputFolderPath.length > 0 && inputCollectionName.length > 0) { + if (inputFolderPath.length > 0) { await watchService.addWatchMapping( - inputCollectionName, + inputFolderPath.substring(inputFolderPath.lastIndexOf('/') + 1), inputFolderPath ); - setInputCollectionName(''); setInputFolderPath(''); setShouldUpdateMappings(true); } @@ -45,37 +39,43 @@ function WatchModal({ watchModalView, setWatchModalView }) { setShouldUpdateMappings(true); }; + const handleClose = () => { + setWatchModalView(false); + }; + return ( - setWatchModalView(false)}> - - Watch Folders - - + +
+ +
+ Watch Folders +
+ + + +
-
@@ -105,7 +106,7 @@ function WatchModal({ watchModalView, setWatchModalView }) {
{mapping.folderPath}{' '} - ))}
- - +
+
); } From cd996a0b49be0da4cd9e16623e0f50abfac69324 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Tue, 7 Jun 2022 12:24:38 +0530 Subject: [PATCH 015/295] sync status button --- src/components/Sidebar/WatchModal.tsx | 51 +++++++++++++++++++++------ src/services/watchService.ts | 4 +++ 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/src/components/Sidebar/WatchModal.tsx b/src/components/Sidebar/WatchModal.tsx index dca115aa48590339b57e4ad230363048056d4025..2f195f97dbe71fe4a2e7197029870ebb0043cad6 100644 --- a/src/components/Sidebar/WatchModal.tsx +++ b/src/components/Sidebar/WatchModal.tsx @@ -1,15 +1,31 @@ import React, { useEffect, useState } from 'react'; -import { Button, Dialog, IconButton } from '@mui/material'; +import { Button, CircularProgress, Dialog, IconButton } from '@mui/material'; import watchService, { WatchMapping } from 'services/watchService'; import { MdDelete } from 'react-icons/md'; import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; import Close from '@mui/icons-material/Close'; import { SpaceBetweenFlex } from 'components/Container'; -function WatchModal({ watchModalView, setWatchModalView }) { +function WatchModal({ + watchModalView, + setWatchModalView, +}: { + watchModalView: boolean; + setWatchModalView: (watchModalView: boolean) => void; +}) { const [mappings, setMappings] = useState([]); const [shouldUpdateMappings, setShouldUpdateMappings] = useState(true); const [inputFolderPath, setInputFolderPath] = useState(''); + const [isSyncing, setIsSyncing] = useState(false); + + useEffect(() => { + if (watchModalView) { + const interval = setInterval(() => { + setIsSyncing(watchService.isEventRunning); + }, 1000); + return () => clearInterval(interval); + } + }, [watchModalView]); useEffect(() => { if (shouldUpdateMappings) { @@ -39,6 +55,12 @@ function WatchModal({ watchModalView, setWatchModalView }) { setShouldUpdateMappings(true); }; + const handleSyncProgressClick = () => { + if (watchService.isUploadRunning) { + // show progress view + } + }; + const handleClose = () => { setWatchModalView(false); }; @@ -103,17 +125,26 @@ function WatchModal({ watchModalView, setWatchModalView }) { -
- Current Watch Mappings -
+
+ Current Watch Mappings +
+ {isSyncing && ( + + + + )} +
(); setElectronFiles: (files: ElectronFile[]) => void; setCollectionName: (collectionName: string) => void; syncWithRemote: () => void; + showProgressView: () => void; constructor() { this.ElectronAPIs = runningInBrowser() && window['ElectronAPIs']; @@ -170,6 +172,7 @@ class WatchService { } this.isEventRunning = true; + this.isUploadRunning = true; this.batchNextEvent(); @@ -282,6 +285,7 @@ class WatchService { this.eventQueue.shift(); this.isEventRunning = false; + this.isUploadRunning = false; this.runNextEvent(); } catch (e) { logError(e, 'error while running all file uploads done'); From 1d9bc49909a88d887af650eec5306232b39a21c9 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Tue, 7 Jun 2022 12:25:49 +0530 Subject: [PATCH 016/295] move watch modal to components --- src/components/Sidebar/UtilitySection.tsx | 2 +- src/components/{Sidebar => }/WatchModal.tsx | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/components/{Sidebar => }/WatchModal.tsx (100%) diff --git a/src/components/Sidebar/UtilitySection.tsx b/src/components/Sidebar/UtilitySection.tsx index 1cddddc199e734477545cc45470b048ab993c753..ee9c2b59048c0a3cae3e8db76cd67cdb484b38aa 100644 --- a/src/components/Sidebar/UtilitySection.tsx +++ b/src/components/Sidebar/UtilitySection.tsx @@ -7,7 +7,7 @@ import TwoFactorModal from 'components/TwoFactor/Modal'; import { PAGES } from 'constants/pages'; import { useRouter } from 'next/router'; import { AppContext } from 'pages/_app'; -import WatchModal from './WatchModal'; +import WatchModal from '../WatchModal'; export default function UtilitySection({ closeSidebar }) { const router = useRouter(); diff --git a/src/components/Sidebar/WatchModal.tsx b/src/components/WatchModal.tsx similarity index 100% rename from src/components/Sidebar/WatchModal.tsx rename to src/components/WatchModal.tsx From fd51318ce6be7057dfb6655ef32fb3958bd38602 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Tue, 7 Jun 2022 15:58:20 +0530 Subject: [PATCH 017/295] show progress view when user clicks on watch modal spinner --- src/components/WatchModal.tsx | 2 +- src/components/pages/gallery/Upload.tsx | 9 +++++++-- src/services/watchService.ts | 4 +++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/components/WatchModal.tsx b/src/components/WatchModal.tsx index 2f195f97dbe71fe4a2e7197029870ebb0043cad6..4fd7b4cc98a5118a1f8016e553b3c19dd045f590 100644 --- a/src/components/WatchModal.tsx +++ b/src/components/WatchModal.tsx @@ -57,7 +57,7 @@ function WatchModal({ const handleSyncProgressClick = () => { if (watchService.isUploadRunning) { - // show progress view + watchService.showProgressView(); } }; diff --git a/src/components/pages/gallery/Upload.tsx b/src/components/pages/gallery/Upload.tsx index 1ea393be4e619957d840c0b1fd7060678db54ede..0a1753be370944a798237dc807d520099a5d28b0 100644 --- a/src/components/pages/gallery/Upload.tsx +++ b/src/components/pages/gallery/Upload.tsx @@ -120,7 +120,8 @@ export default function Upload(props: Props) { watchService.setWatchServiceFunctions( props.setElectronFiles, setCollectionName, - props.syncWithRemote + props.syncWithRemote, + showProgressView ); watchService.init(); } @@ -131,6 +132,10 @@ export default function Upload(props: Props) { pendingDesktopUploadCollectionName.current = collectionName; }; + const showProgressView = () => { + setProgressView(true); + }; + useEffect(() => { if ( props.electronFiles?.length > 0 || @@ -185,7 +190,7 @@ export default function Upload(props: Props) { setUploadResult(new Map()); setPercentComplete(0); props.closeCollectionSelector(); - setProgressView(true); + !watchService.isUploadRunning && setProgressView(true); // don't show progress view if upload triggered by watch service }; const resumeDesktopUpload = async ( diff --git a/src/services/watchService.ts b/src/services/watchService.ts index 94ad79510c8ff5dde91138c1e48676efb2f296ff..f12633bbc89f5512fa7737a6cd205a818f07ca10 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -42,11 +42,13 @@ class WatchService { setWatchServiceFunctions( setElectronFiles: (files: ElectronFile[]) => void, setCollectionName: (collectionName: string) => void, - syncWithRemote: () => void + syncWithRemote: () => void, + showProgressView: () => void ) { this.setElectronFiles = setElectronFiles; this.setCollectionName = setCollectionName; this.syncWithRemote = syncWithRemote; + this.showProgressView = showProgressView; } async init() { From 6182249b5fa2c92568b5a689559265e98ab4a920 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Tue, 7 Jun 2022 16:50:25 +0530 Subject: [PATCH 018/295] ignore trashing files if root mapping directory is deleted --- src/services/watchService.ts | 38 +++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/services/watchService.ts b/src/services/watchService.ts index f12633bbc89f5512fa7737a6cd205a818f07ca10..38ea9d284b467149f9f656423d5464d31d68c92e 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -26,6 +26,7 @@ class WatchService { ElectronAPIs: any; allElectronAPIsExist: boolean = false; eventQueue: EventQueueType[] = []; + trashingDirQueue: string[] = []; isEventRunning: boolean = false; isUploadRunning: boolean = false; pathToIDMap = new Map(); @@ -303,6 +304,14 @@ class WatchService { this.isEventRunning = true; + if (this.trashingDirQueue.length !== 0) { + this.removeFilesMatchingTrashingDir(this.trashingDirQueue[0]); + this.trashingDirQueue.shift(); + this.isEventRunning = false; + this.runNextEvent(); + return; + } + this.batchNextEvent(); const { collectionName, paths } = this.eventQueue[0]; @@ -367,6 +376,12 @@ class WatchService { } } + removeFilesMatchingTrashingDir(trashingDir: string) { + this.eventQueue = this.eventQueue.filter((event) => + event.paths.every((path) => !path.startsWith(trashingDir)) + ); + } + async getCollectionName(filePath: string) { try { const mappings = this.getWatchMappings(); @@ -439,7 +454,8 @@ async function diskFileAddedCallback(instance: WatchService, filePath: string) { async function diskFileRemovedCallback( instance: WatchService, - filePath: string + filePath: string, + isDir?: boolean ) { try { const collectionName = await instance.getCollectionName(filePath); @@ -450,6 +466,14 @@ async function diskFileRemovedCallback( return; } + if ( + isDir && + hasMappingSameFolderPath(instance, collectionName, filePath) + ) { + instance.trashingDirQueue.push(filePath); + return; + } + const event: EventQueueType = { type: 'trash', collectionName, @@ -466,4 +490,16 @@ const runNextEventByInstance = async (w: WatchService) => { await w.runNextEvent(); }; +const hasMappingSameFolderPath = ( + w: WatchService, + collectionName: string, + folderPath: string +) => { + const mappings = w.getWatchMappings(); + const mapping = mappings.find( + (mapping) => mapping.collectionName === collectionName + ); + return mapping.folderPath === folderPath; +}; + export default new WatchService(); From 07fea0bc556244c4857fcdb5b9e9de6f3d6847d8 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Tue, 7 Jun 2022 17:13:57 +0530 Subject: [PATCH 019/295] remove mappings whose folders don't exist --- src/services/watchService.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/services/watchService.ts b/src/services/watchService.ts index 38ea9d284b467149f9f656423d5464d31d68c92e..c1228c89a322d016b9a9f52cece172c5a95c020c 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -55,7 +55,7 @@ class WatchService { async init() { if (this.allElectronAPIsExist) { try { - const mappings = this.getWatchMappings(); + let mappings = this.getWatchMappings(); console.log('mappings', mappings); @@ -63,6 +63,19 @@ class WatchService { return; } + const existingMappings = []; + for (const mapping of mappings) { + const mappingExists = + await this.ElectronAPIs.isFolderExists( + mapping.folderPath + ); + if (mappingExists) { + existingMappings.push(mapping); + } + } + this.ElectronAPIs.setWatchMappings(existingMappings); + mappings = existingMappings; + for (const mapping of mappings) { const filePathsOnDisk: string[] = await this.ElectronAPIs.getPosixFilePathsFromDir( From ae24b70c4b652d581aefcec3c6ecd598f6081159 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Wed, 8 Jun 2022 23:10:15 +0530 Subject: [PATCH 020/295] refactor --- src/components/WatchModal.tsx | 31 ++--- src/components/pages/gallery/Upload.tsx | 8 +- src/pages/_app.tsx | 5 + src/services/upload/uploadManager.ts | 2 +- src/services/watchService.ts | 159 +++++++++++------------- src/types/watch/index.ts | 14 +++ 6 files changed, 104 insertions(+), 115 deletions(-) create mode 100644 src/types/watch/index.ts diff --git a/src/components/WatchModal.tsx b/src/components/WatchModal.tsx index 4fd7b4cc98a5118a1f8016e553b3c19dd045f590..362175f81c63817765112e2ab1f70ecb52636ad0 100644 --- a/src/components/WatchModal.tsx +++ b/src/components/WatchModal.tsx @@ -1,10 +1,12 @@ import React, { useEffect, useState } from 'react'; import { Button, CircularProgress, Dialog, IconButton } from '@mui/material'; -import watchService, { WatchMapping } from 'services/watchService'; +import watchService from 'services/watchService'; import { MdDelete } from 'react-icons/md'; import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; import Close from '@mui/icons-material/Close'; import { SpaceBetweenFlex } from 'components/Container'; +import { WatchMapping } from 'types/watch'; +import { AppContext } from 'pages/_app'; function WatchModal({ watchModalView, @@ -14,25 +16,12 @@ function WatchModal({ setWatchModalView: (watchModalView: boolean) => void; }) { const [mappings, setMappings] = useState([]); - const [shouldUpdateMappings, setShouldUpdateMappings] = useState(true); const [inputFolderPath, setInputFolderPath] = useState(''); - const [isSyncing, setIsSyncing] = useState(false); + const appContext = React.useContext(AppContext); useEffect(() => { - if (watchModalView) { - const interval = setInterval(() => { - setIsSyncing(watchService.isEventRunning); - }, 1000); - return () => clearInterval(interval); - } - }, [watchModalView]); - - useEffect(() => { - if (shouldUpdateMappings) { - setMappings(watchService.getWatchMappings()); - setShouldUpdateMappings(false); - } - }, [shouldUpdateMappings]); + setMappings(watchService.getWatchMappings()); + }, []); const handleFolderSelection = async () => { const folderPath = await watchService.selectFolder(); @@ -46,17 +35,17 @@ function WatchModal({ inputFolderPath ); setInputFolderPath(''); - setShouldUpdateMappings(true); + setMappings(watchService.getWatchMappings()); } }; const handleRemoveWatchMapping = async (mapping: WatchMapping) => { await watchService.removeWatchMapping(mapping.collectionName); - setShouldUpdateMappings(true); + setMappings(watchService.getWatchMappings()); }; const handleSyncProgressClick = () => { - if (watchService.isUploadRunning) { + if (watchService.isUploadRunning()) { watchService.showProgressView(); } }; @@ -139,7 +128,7 @@ function WatchModal({ }}> Current Watch Mappings
- {isSyncing && ( + {appContext.watchServiceIsRunning && ( diff --git a/src/components/pages/gallery/Upload.tsx b/src/components/pages/gallery/Upload.tsx index 0a1753be370944a798237dc807d520099a5d28b0..d177fbec78ea4d36537deafd1fd71e5b2cdeab7f 100644 --- a/src/components/pages/gallery/Upload.tsx +++ b/src/components/pages/gallery/Upload.tsx @@ -117,13 +117,13 @@ export default function Upload(props: Props) { resumeDesktopUpload(type, electronFiles, collectionName); } ); - watchService.setWatchServiceFunctions( + watchService.init( props.setElectronFiles, setCollectionName, props.syncWithRemote, - showProgressView + showProgressView, + appContext.setWatchServiceIsRunning ); - watchService.init(); } }, []); @@ -190,7 +190,7 @@ export default function Upload(props: Props) { setUploadResult(new Map()); setPercentComplete(0); props.closeCollectionSelector(); - !watchService.isUploadRunning && setProgressView(true); // don't show progress view if upload triggered by watch service + !watchService.isUploadRunning() && setProgressView(true); // don't show progress view if upload triggered by watch service }; const resumeDesktopUpload = async ( diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 04ed9d21016098733aef1b16393c6b6441fc8d34..6d541a6f39dabba83d52488bb9ae286301f74e38 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -58,6 +58,8 @@ type AppContextType = { finishLoading: () => void; closeMessageDialog: () => void; setDialogMessage: SetDialogBoxAttributes; + watchServiceIsRunning: boolean; + setWatchServiceIsRunning: (isRunning: boolean) => void; }; export enum FLASH_MESSAGE_TYPE { @@ -92,6 +94,7 @@ export default function App({ Component, err }) { const loadingBar = useRef(null); const [dialogMessage, setDialogMessage] = useState(); const [messageDialogView, setMessageDialogView] = useState(false); + const [watchServiceIsRunning, setWatchServiceIsRunning] = useState(false); useEffect(() => { if ( @@ -284,6 +287,8 @@ export default function App({ Component, err }) { finishLoading, closeMessageDialog, setDialogMessage, + watchServiceIsRunning, + setWatchServiceIsRunning, }}> {loading ? ( diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index e4c7c144fea811778da6257cc3af9f3c765acab6..378cc35f6f8139cb414b8dd58737d3581f4291c5 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -407,7 +407,7 @@ class UploadManager { FileUploadResults.UPLOADED_WITH_STATIC_THUMBNAIL || fileUploadResult === FileUploadResults.ALREADY_UPLOADED ) { - await watchService.fileUploaded( + await watchService.onFileUpload( fileWithCollection, uploadedFile ); diff --git a/src/services/watchService.ts b/src/services/watchService.ts index c1228c89a322d016b9a9f52cece172c5a95c020c..7cb9c757b62f4bdc78c80c8314f4ae85fe39e466 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -6,55 +6,47 @@ import { removeFromCollection, syncCollections } from './collectionService'; import { syncFiles } from './fileService'; import debounce from 'debounce-promise'; import { logError } from 'utils/sentry'; - -export interface WatchMapping { - collectionName: string; - folderPath: string; - files: { - path: string; - id: number; - }[]; -} - -interface EventQueueType { - type: 'upload' | 'trash'; - collectionName: string; - paths: string[]; -} +import { EventQueueType, WatchMapping } from 'types/watch'; class WatchService { ElectronAPIs: any; allElectronAPIsExist: boolean = false; eventQueue: EventQueueType[] = []; + currentEvent: EventQueueType; trashingDirQueue: string[] = []; isEventRunning: boolean = false; - isUploadRunning: boolean = false; + uploadRunning: boolean = false; pathToIDMap = new Map(); setElectronFiles: (files: ElectronFile[]) => void; setCollectionName: (collectionName: string) => void; syncWithRemote: () => void; showProgressView: () => void; + setWatchServiceIsRunning: (isRunning: boolean) => void; constructor() { this.ElectronAPIs = runningInBrowser() && window['ElectronAPIs']; this.allElectronAPIsExist = !!this.ElectronAPIs?.getWatchMappings; } - setWatchServiceFunctions( + isUploadRunning() { + return this.uploadRunning; + } + + async init( setElectronFiles: (files: ElectronFile[]) => void, setCollectionName: (collectionName: string) => void, syncWithRemote: () => void, - showProgressView: () => void + showProgressView: () => void, + setWatchServiceIsRunning: (isRunning: boolean) => void ) { - this.setElectronFiles = setElectronFiles; - this.setCollectionName = setCollectionName; - this.syncWithRemote = syncWithRemote; - this.showProgressView = showProgressView; - } - - async init() { if (this.allElectronAPIsExist) { try { + this.setElectronFiles = setElectronFiles; + this.setCollectionName = setCollectionName; + this.syncWithRemote = syncWithRemote; + this.showProgressView = showProgressView; + this.setWatchServiceIsRunning = setWatchServiceIsRunning; + let mappings = this.getWatchMappings(); console.log('mappings', mappings); @@ -63,18 +55,7 @@ class WatchService { return; } - const existingMappings = []; - for (const mapping of mappings) { - const mappingExists = - await this.ElectronAPIs.isFolderExists( - mapping.folderPath - ); - if (mappingExists) { - existingMappings.push(mapping); - } - } - this.ElectronAPIs.setWatchMappings(existingMappings); - mappings = existingMappings; + mappings = await this.filterOutDeletedMappings(mappings); for (const mapping of mappings) { const filePathsOnDisk: string[] = @@ -114,7 +95,6 @@ class WatchService { } this.setWatchFunctions(); - this.syncWithRemote(); await this.runNextEvent(); } catch (e) { logError(e, 'error while initializing watch service'); @@ -122,6 +102,22 @@ class WatchService { } } + async filterOutDeletedMappings( + mappings: WatchMapping[] + ): Promise { + const notDeletedMappings = []; + for (const mapping of mappings) { + const mappingExists = await this.ElectronAPIs.isFolderExists( + mapping.folderPath + ); + if (mappingExists) { + notDeletedMappings.push(mapping); + } + } + this.ElectronAPIs.setWatchMappings(notDeletedMappings); + return notDeletedMappings; + } + setWatchFunctions() { if (this.allElectronAPIsExist) { this.ElectronAPIs.registerWatcherFunctions( @@ -167,6 +163,11 @@ class WatchService { return []; } + setIsEventRunning(isEventRunning: boolean) { + this.isEventRunning = isEventRunning; + this.setWatchServiceIsRunning(isEventRunning); + } + async runNextEvent() { console.log('runNextEvent mappings', this.getWatchMappings()); @@ -174,28 +175,24 @@ class WatchService { return; } - if (this.eventQueue[0].type === 'upload') { - this.runNextUpload(); + this.setIsEventRunning(true); + const event = this.clubSameCollectionEvents(); + this.currentEvent = event; + if (event.type === 'upload') { + this.processUploadEvent(); } else { - this.runNextTrash(); + this.processTrashEvent(); } } - private async runNextUpload() { + private async processUploadEvent() { try { - if (this.eventQueue.length === 0 || this.isEventRunning) { - return; - } - - this.isEventRunning = true; - this.isUploadRunning = true; + this.uploadRunning = true; - this.batchNextEvent(); - - this.setCollectionName(this.eventQueue[0].collectionName); + this.setCollectionName(this.currentEvent.collectionName); this.setElectronFiles( await Promise.all( - this.eventQueue[0].paths.map(async (path) => { + this.currentEvent.paths.map(async (path) => { return await this.ElectronAPIs.getElectronFile(path); }) ) @@ -205,7 +202,7 @@ class WatchService { } } - async fileUploaded(fileWithCollection: FileWithCollection, file: EnteFile) { + async onFileUpload(fileWithCollection: FileWithCollection, file: EnteFile) { if (fileWithCollection.isLivePhoto) { this.pathToIDMap.set( (fileWithCollection.livePhotoAssets.image as ElectronFile).path, @@ -235,8 +232,7 @@ class WatchService { ); if ( !this.isEventRunning || - this.eventQueue.length === 0 || - this.eventQueue[0].collectionName !== collection?.name + this.currentEvent.collectionName !== collection?.name ) { return; } @@ -291,7 +287,7 @@ class WatchService { const mapping = mappings.find( (mapping) => mapping.collectionName === - this.eventQueue[0].collectionName + this.currentEvent.collectionName ); mapping.files = [...mapping.files, ...uploadedFiles]; @@ -299,9 +295,8 @@ class WatchService { this.syncWithRemote(); } - this.eventQueue.shift(); - this.isEventRunning = false; - this.isUploadRunning = false; + this.setIsEventRunning(false); + this.uploadRunning = false; this.runNextEvent(); } catch (e) { logError(e, 'error while running all file uploads done'); @@ -309,25 +304,17 @@ class WatchService { } } - private async runNextTrash() { + private async processTrashEvent() { try { - if (this.eventQueue.length === 0 || this.isEventRunning) { - return; - } - - this.isEventRunning = true; - if (this.trashingDirQueue.length !== 0) { - this.removeFilesMatchingTrashingDir(this.trashingDirQueue[0]); + this.ignoreFileEventsFromTrashedDir(this.trashingDirQueue[0]); this.trashingDirQueue.shift(); - this.isEventRunning = false; + this.setIsEventRunning(false); this.runNextEvent(); return; } - this.batchNextEvent(); - - const { collectionName, paths } = this.eventQueue[0]; + const { collectionName, paths } = this.currentEvent; const filePathsToRemove = new Set(paths); const mappings = this.getWatchMappings(); @@ -350,8 +337,7 @@ class WatchService { this.ElectronAPIs.setWatchMappings(mappings); this.syncWithRemote(); - this.eventQueue.shift(); - this.isEventRunning = false; + this.setIsEventRunning(false); this.runNextEvent(); } catch (e) { logError(e, 'error while running next trash'); @@ -389,7 +375,7 @@ class WatchService { } } - removeFilesMatchingTrashingDir(trashingDir: string) { + ignoreFileEventsFromTrashedDir(trashingDir: string) { this.eventQueue = this.eventQueue.filter((event) => event.paths.every((path) => !path.startsWith(trashingDir)) ); @@ -424,22 +410,17 @@ class WatchService { // Batches all the files to be uploaded (or trashed) from the // event queue of same collection as the next event - private batchNextEvent() { - const newEventQueue = [this.eventQueue[0]]; - const len = this.eventQueue.length; - for (let i = 1; i < len; i++) { - if ( - this.eventQueue[i].collectionName === - newEventQueue[0].collectionName && - this.eventQueue[i].type === newEventQueue[0].type - ) { - newEventQueue[0].paths.push(...this.eventQueue[i].paths); - } else { - newEventQueue.push(this.eventQueue[i]); - } + private clubSameCollectionEvents(): EventQueueType { + const event = this.eventQueue.shift(); + while ( + this.eventQueue.length > 0 && + event.collectionName === this.eventQueue[0].collectionName && + event.type === this.eventQueue[0].type + ) { + event.paths = [...event.paths, ...this.eventQueue[0].paths]; + this.eventQueue.shift(); } - newEventQueue.push(...this.eventQueue.slice(len)); - this.eventQueue = newEventQueue; + return event; } } diff --git a/src/types/watch/index.ts b/src/types/watch/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..a8481a6a6c19f316bab52705df408a3d54b56932 --- /dev/null +++ b/src/types/watch/index.ts @@ -0,0 +1,14 @@ +export interface WatchMapping { + collectionName: string; + folderPath: string; + files: { + path: string; + id: number; + }[]; +} + +export interface EventQueueType { + type: 'upload' | 'trash'; + collectionName: string; + paths: string[]; +} From aa8483d4da878f98862d1694d413fc9618b41896 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Wed, 8 Jun 2022 23:23:18 +0530 Subject: [PATCH 021/295] rename and refactor --- src/services/upload/uploader.ts | 23 +++++++++++++---------- src/services/watchService.ts | 15 +++++++++++---- src/utils/upload/index.ts | 2 +- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/services/upload/uploader.ts b/src/services/upload/uploader.ts index 166a6e454a5ff03df7e0868b56a6c40385383025..0d76a23af59a1eb0f5a327ca19b1dc4a79d8f8f4 100644 --- a/src/services/upload/uploader.ts +++ b/src/services/upload/uploader.ts @@ -2,7 +2,7 @@ import { EnteFile } from 'types/file'; import { handleUploadError, CustomError } from 'utils/error'; import { logError } from 'utils/sentry'; import { - fileAlreadyInCollection, + findSameFileInCollection, findSameFileInOtherCollection, shouldDedupeAcrossCollection, } from 'utils/upload'; @@ -50,7 +50,7 @@ export default async function uploader( throw Error(CustomError.NO_METADATA); } - const sameFileInSameCollection = fileAlreadyInCollection( + const sameFileInSameCollection = findSameFileInCollection( existingFilesInCollection, metadata ); @@ -84,15 +84,18 @@ export default async function uploader( // iOS exports via album doesn't export files without collection and if user exports all photos, album info is not preserved. // This change allow users to export by albums, upload to ente. And export all photos -> upload files which are not already uploaded // as part of the albums - if ( - shouldDedupeAcrossCollection(fileWithCollection.collection.name) && - fileAlreadyInCollection(existingFiles, metadata) - ) { + if (shouldDedupeAcrossCollection(fileWithCollection.collection.name)) { logUploadInfo(`deduped upload for ${fileNameSize}`); - return { - fileUploadResult: FileUploadResults.ALREADY_UPLOADED, - uploadedFile: fileAlreadyInCollection(existingFiles, metadata), - }; + const sameFileInOtherCollection = findSameFileInCollection( + existingFiles, + metadata + ); + if (sameFileInOtherCollection) { + return { + fileUploadResult: FileUploadResults.ALREADY_UPLOADED, + uploadedFile: sameFileInOtherCollection, + }; + } } logUploadInfo(`reading asset ${fileNameSize}`); diff --git a/src/services/watchService.ts b/src/services/watchService.ts index 7cb9c757b62f4bdc78c80c8314f4ae85fe39e466..056fef7b9f6cf2efdf3db5e86c5b1b09686b7d64 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -306,10 +306,7 @@ class WatchService { private async processTrashEvent() { try { - if (this.trashingDirQueue.length !== 0) { - this.ignoreFileEventsFromTrashedDir(this.trashingDirQueue[0]); - this.trashingDirQueue.shift(); - this.setIsEventRunning(false); + if (this.checkAndRemoveIfFileEventsFromTrashedDir()) { this.runNextEvent(); return; } @@ -375,6 +372,16 @@ class WatchService { } } + checkAndRemoveIfFileEventsFromTrashedDir() { + if (this.trashingDirQueue.length !== 0) { + this.ignoreFileEventsFromTrashedDir(this.trashingDirQueue[0]); + this.trashingDirQueue.shift(); + this.setIsEventRunning(false); + return true; + } + return false; + } + ignoreFileEventsFromTrashedDir(trashingDir: string) { this.eventQueue = this.eventQueue.filter((event) => event.paths.every((path) => !path.startsWith(trashingDir)) diff --git a/src/utils/upload/index.ts b/src/utils/upload/index.ts index 12668484056b8df220ceca0bb9c14e2a794a102b..71a27f47bcd62445a18cafc20d51502bf6cfe843 100644 --- a/src/utils/upload/index.ts +++ b/src/utils/upload/index.ts @@ -9,7 +9,7 @@ import { FILE_TYPE } from 'constants/file'; const TYPE_JSON = 'json'; const DEDUPE_COLLECTION = new Set(['icloud library', 'icloudlibrary']); -export function fileAlreadyInCollection( +export function findSameFileInCollection( existingFilesInCollection: EnteFile[], newFileMetadata: Metadata ): EnteFile { From ac5c8069f37c306779a5e39cd310bdf94180f3f3 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Thu, 9 Jun 2022 11:06:40 +0530 Subject: [PATCH 022/295] refactor to directly use electron files for upload --- src/services/watchService.ts | 184 +++++++++++++++++++---------------- src/types/watch/index.ts | 5 +- 2 files changed, 104 insertions(+), 85 deletions(-) diff --git a/src/services/watchService.ts b/src/services/watchService.ts index 056fef7b9f6cf2efdf3db5e86c5b1b09686b7d64..cc3be14eb2d5ea69a40c5b5e1a8cfb12b661b40f 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -58,40 +58,13 @@ class WatchService { mappings = await this.filterOutDeletedMappings(mappings); for (const mapping of mappings) { - const filePathsOnDisk: string[] = - await this.ElectronAPIs.getPosixFilePathsFromDir( + const filesOnDisk: ElectronFile[] = + await this.ElectronAPIs.getAllFilesFromDir( mapping.folderPath ); - const filesToUpload = filePathsOnDisk.filter((filePath) => { - return !mapping.files.find( - (file) => file.path === filePath - ); - }); - - const filesToRemove = mapping.files.filter((file) => { - return !filePathsOnDisk.find( - (filePath) => filePath === file.path - ); - }); - - if (filesToUpload.length > 0) { - const event: EventQueueType = { - type: 'upload', - collectionName: mapping.collectionName, - paths: filesToUpload, - }; - this.eventQueue.push(event); - } - - if (filesToRemove.length > 0) { - const event: EventQueueType = { - type: 'trash', - collectionName: mapping.collectionName, - paths: filesToRemove.map((file) => file.path), - }; - this.eventQueue.push(event); - } + this.uploadDiffOfFiles(mapping, filesOnDisk); + this.trashDiffOfFiles(mapping, filesOnDisk); } this.setWatchFunctions(); @@ -102,6 +75,46 @@ class WatchService { } } + private uploadDiffOfFiles( + mapping: WatchMapping, + filesOnDisk: ElectronFile[] + ) { + const filesToUpload = filesOnDisk.filter((electronFile) => { + return !mapping.files.find( + (file) => file.path === electronFile.path + ); + }); + + if (filesToUpload.length > 0) { + const event: EventQueueType = { + type: 'upload', + collectionName: mapping.collectionName, + files: filesToUpload, + }; + this.eventQueue.push(event); + } + } + + private trashDiffOfFiles( + mapping: WatchMapping, + filesOnDisk: ElectronFile[] + ) { + const filesToRemove = mapping.files.filter((file) => { + return !filesOnDisk.find( + (electronFile) => electronFile.path === file.path + ); + }); + + if (filesToRemove.length > 0) { + const event: EventQueueType = { + type: 'trash', + collectionName: mapping.collectionName, + paths: filesToRemove.map((file) => file.path), + }; + this.eventQueue.push(event); + } + } + async filterOutDeletedMappings( mappings: WatchMapping[] ): Promise { @@ -190,19 +203,16 @@ class WatchService { this.uploadRunning = true; this.setCollectionName(this.currentEvent.collectionName); - this.setElectronFiles( - await Promise.all( - this.currentEvent.paths.map(async (path) => { - return await this.ElectronAPIs.getElectronFile(path); - }) - ) - ); + this.setElectronFiles(this.currentEvent.files); } catch (e) { logError(e, 'error while running next upload'); } } async onFileUpload(fileWithCollection: FileWithCollection, file: EnteFile) { + if (!this.isUploadRunning) { + return; + } if (fileWithCollection.isLivePhoto) { this.pathToIDMap.set( (fileWithCollection.livePhotoAssets.image as ElectronFile).path, @@ -240,46 +250,7 @@ class WatchService { const uploadedFiles: WatchMapping['files'] = []; for (const fileWithCollection of filesWithCollection) { - if (fileWithCollection.isLivePhoto) { - const imagePath = ( - fileWithCollection.livePhotoAssets - .image as ElectronFile - ).path; - const videoPath = ( - fileWithCollection.livePhotoAssets - .video as ElectronFile - ).path; - - if ( - this.pathToIDMap.has(imagePath) && - this.pathToIDMap.has(videoPath) - ) { - uploadedFiles.push({ - path: imagePath, - id: this.pathToIDMap.get(imagePath), - }); - uploadedFiles.push({ - path: videoPath, - id: this.pathToIDMap.get(videoPath), - }); - - this.pathToIDMap.delete(imagePath); - this.pathToIDMap.delete(videoPath); - } - } else { - const filePath = ( - fileWithCollection.file as ElectronFile - ).path; - - if (this.pathToIDMap.has(filePath)) { - uploadedFiles.push({ - path: filePath, - id: this.pathToIDMap.get(filePath), - }); - - this.pathToIDMap.delete(filePath); - } - } + this.handleUploadedFile(fileWithCollection, uploadedFiles); } if (uploadedFiles.length > 0) { @@ -304,9 +275,51 @@ class WatchService { } } + private handleUploadedFile( + fileWithCollection: FileWithCollection, + uploadedFiles: { path: string; id: number }[] + ) { + if (fileWithCollection.isLivePhoto) { + const imagePath = ( + fileWithCollection.livePhotoAssets.image as ElectronFile + ).path; + const videoPath = ( + fileWithCollection.livePhotoAssets.video as ElectronFile + ).path; + + if ( + this.pathToIDMap.has(imagePath) && + this.pathToIDMap.has(videoPath) + ) { + uploadedFiles.push({ + path: imagePath, + id: this.pathToIDMap.get(imagePath), + }); + uploadedFiles.push({ + path: videoPath, + id: this.pathToIDMap.get(videoPath), + }); + + this.pathToIDMap.delete(imagePath); + this.pathToIDMap.delete(videoPath); + } + } else { + const filePath = (fileWithCollection.file as ElectronFile).path; + + if (this.pathToIDMap.has(filePath)) { + uploadedFiles.push({ + path: filePath, + id: this.pathToIDMap.get(filePath), + }); + + this.pathToIDMap.delete(filePath); + } + } + } + private async processTrashEvent() { try { - if (this.checkAndRemoveIfFileEventsFromTrashedDir()) { + if (this.checkAndIgnoreIfFileEventsFromTrashedDir()) { this.runNextEvent(); return; } @@ -372,7 +385,7 @@ class WatchService { } } - checkAndRemoveIfFileEventsFromTrashedDir() { + checkAndIgnoreIfFileEventsFromTrashedDir() { if (this.trashingDirQueue.length !== 0) { this.ignoreFileEventsFromTrashedDir(this.trashingDirQueue[0]); this.trashingDirQueue.shift(); @@ -431,20 +444,23 @@ class WatchService { } } -async function diskFileAddedCallback(instance: WatchService, filePath: string) { +async function diskFileAddedCallback( + instance: WatchService, + file: ElectronFile +) { try { - const collectionName = await instance.getCollectionName(filePath); + const collectionName = await instance.getCollectionName(file.path); if (!collectionName) { return; } - console.log('added (upload) to event queue', collectionName, filePath); + console.log('added (upload) to event queue', collectionName, file); const event: EventQueueType = { type: 'upload', collectionName, - paths: [filePath], + files: [file], }; instance.eventQueue.push(event); await debounce(runNextEventByInstance, 300)(instance); diff --git a/src/types/watch/index.ts b/src/types/watch/index.ts index a8481a6a6c19f316bab52705df408a3d54b56932..b34594e359e13de20db5f2de61c4043015708685 100644 --- a/src/types/watch/index.ts +++ b/src/types/watch/index.ts @@ -1,3 +1,5 @@ +import { ElectronFile } from 'types/upload'; + export interface WatchMapping { collectionName: string; folderPath: string; @@ -10,5 +12,6 @@ export interface WatchMapping { export interface EventQueueType { type: 'upload' | 'trash'; collectionName: string; - paths: string[]; + paths?: string[]; + files?: ElectronFile[]; } From 6ba67f1c02d04055fa6e8a76092d75493f245ecc Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Thu, 9 Jun 2022 11:26:33 +0530 Subject: [PATCH 023/295] refactor --- src/services/watchService.ts | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/services/watchService.ts b/src/services/watchService.ts index cc3be14eb2d5ea69a40c5b5e1a8cfb12b661b40f..52b2dc5a53441ff9a39336afbc0df2dae9cc1d41 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -120,7 +120,7 @@ class WatchService { ): Promise { const notDeletedMappings = []; for (const mapping of mappings) { - const mappingExists = await this.ElectronAPIs.isFolderExists( + const mappingExists = await this.ElectronAPIs.doesFolderExists( mapping.folderPath ); if (mappingExists) { @@ -136,7 +136,8 @@ class WatchService { this.ElectronAPIs.registerWatcherFunctions( this, diskFileAddedCallback, - diskFileRemovedCallback + diskFileRemovedCallback, + diskFolderRemovedCallback ); } } @@ -471,8 +472,7 @@ async function diskFileAddedCallback( async function diskFileRemovedCallback( instance: WatchService, - filePath: string, - isDir?: boolean + filePath: string ) { try { const collectionName = await instance.getCollectionName(filePath); @@ -483,14 +483,6 @@ async function diskFileRemovedCallback( return; } - if ( - isDir && - hasMappingSameFolderPath(instance, collectionName, filePath) - ) { - instance.trashingDirQueue.push(filePath); - return; - } - const event: EventQueueType = { type: 'trash', collectionName, @@ -503,6 +495,24 @@ async function diskFileRemovedCallback( } } +async function diskFolderRemovedCallback( + instance: WatchService, + folderPath: string +) { + try { + const collectionName = await instance.getCollectionName(folderPath); + if (!collectionName) { + return; + } + + if (hasMappingSameFolderPath(instance, collectionName, folderPath)) { + instance.trashingDirQueue.push(folderPath); + } + } catch (e) { + logError(e, 'error while calling diskFolderRemovedCallback'); + } +} + const runNextEventByInstance = async (w: WatchService) => { await w.runNextEvent(); }; From ae6251968c346596be0e0a37c3db36d807b286ed Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Thu, 9 Jun 2022 16:07:17 +0530 Subject: [PATCH 024/295] rename API func --- src/services/watchService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/watchService.ts b/src/services/watchService.ts index 52b2dc5a53441ff9a39336afbc0df2dae9cc1d41..3399767537bf8faf4d2819e46c8caa542a4be535 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -422,7 +422,7 @@ class WatchService { async selectFolder(): Promise { try { - const folderPath = await this.ElectronAPIs.selectFolder(); + const folderPath = await this.ElectronAPIs.selectRootDirectory(); return folderPath; } catch (e) { logError(e, 'error while selecting folder'); From 8b83869e42e1f07b6e2aab94f825bfb8222eb876 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Thu, 9 Jun 2022 16:25:48 +0530 Subject: [PATCH 025/295] added types for ElectronAPIs --- src/services/exportService.ts | 3 +- src/services/importService.ts | 3 +- src/services/watchService.ts | 8 +++-- src/types/electron/index.ts | 65 +++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 src/types/electron/index.ts diff --git a/src/services/exportService.ts b/src/services/exportService.ts index 3e413576aeecbd08bfee98a2dc4e83a68c5c8793..d7c9aa0e5b0bdad7ae18f08bedd605375afd6b4e 100644 --- a/src/services/exportService.ts +++ b/src/services/exportService.ts @@ -50,12 +50,13 @@ import { import { User } from 'types/user'; import { FILE_TYPE, TYPE_JPEG, TYPE_JPG } from 'constants/file'; import { ExportType, ExportNotification, RecordType } from 'constants/export'; +import { ElectronAPIsInterface } from 'types/electron'; const LATEST_EXPORT_VERSION = 1; const EXPORT_RECORD_FILE_NAME = 'export_status.json'; class ExportService { - ElectronAPIs: any; + ElectronAPIs: ElectronAPIsInterface; private exportInProgress: Promise<{ paused: boolean }> = null; private exportRecordUpdater = new QueueProcessor(1); diff --git a/src/services/importService.ts b/src/services/importService.ts index 5feb85b81278c474adc11dcdde3a566b7ba106e0..437024d4b46883bdb9283a204ffeeec549e776f0 100644 --- a/src/services/importService.ts +++ b/src/services/importService.ts @@ -1,5 +1,6 @@ import { DESKTOP_UPLOAD_TYPE } from 'components/pages/gallery/Upload'; import { Collection } from 'types/collection'; +import { ElectronAPIsInterface } from 'types/electron'; import { ElectronFile, FileWithCollection } from 'types/upload'; import { runningInBrowser } from 'utils/common'; import { logError } from 'utils/sentry'; @@ -15,7 +16,7 @@ interface selectZipResult { zipPaths: string[]; } class ImportService { - ElectronAPIs: any; + ElectronAPIs: ElectronAPIsInterface; private allElectronAPIsExist: boolean = false; constructor() { diff --git a/src/services/watchService.ts b/src/services/watchService.ts index 3399767537bf8faf4d2819e46c8caa542a4be535..7b5cd5775953ef7e28563940ea2bd71b6700e077 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -7,9 +7,10 @@ import { syncFiles } from './fileService'; import debounce from 'debounce-promise'; import { logError } from 'utils/sentry'; import { EventQueueType, WatchMapping } from 'types/watch'; +import { ElectronAPIsInterface } from 'types/electron'; -class WatchService { - ElectronAPIs: any; +export class WatchService { + ElectronAPIs: ElectronAPIsInterface; allElectronAPIsExist: boolean = false; eventQueue: EventQueueType[] = []; currentEvent: EventQueueType; @@ -24,7 +25,8 @@ class WatchService { setWatchServiceIsRunning: (isRunning: boolean) => void; constructor() { - this.ElectronAPIs = runningInBrowser() && window['ElectronAPIs']; + this.ElectronAPIs = (runningInBrowser() && + window['ElectronAPIs']) as ElectronAPIsInterface; this.allElectronAPIsExist = !!this.ElectronAPIs?.getWatchMappings; } diff --git a/src/types/electron/index.ts b/src/types/electron/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..c5705b5b59ee177d0380d31e2976ea2278a09dc8 --- /dev/null +++ b/src/types/electron/index.ts @@ -0,0 +1,65 @@ +import { WatchService } from 'services/watchService'; +import { ElectronFile } from 'types/upload'; +import { WatchMapping } from 'types/watch'; + +export interface ElectronAPIsInterface { + exists: (path: string) => boolean; + checkExistsAndCreateCollectionDir: (dirPath: string) => Promise; + checkExistsAndRename: ( + oldDirPath: string, + newDirPath: string + ) => Promise; + saveStreamToDisk: (path: string, fileStream: ReadableStream) => void; + saveFileToDisk: (path: string, file: any) => Promise; + selectRootDirectory: () => Promise; + sendNotification: (content: string) => void; + showOnTray: (content?: any) => void; + reloadWindow: () => void; + registerResumeExportListener: (resumeExport: () => void) => void; + registerStopExportListener: (abortExport: () => void) => void; + registerPauseExportListener: (pauseExport: () => void) => void; + registerRetryFailedExportListener: (retryFailedExport: () => void) => void; + getExportRecord: (filePath: string) => Promise; + setExportRecord: (filePath: string, data: string) => Promise; + getElectronFile: (filePath: string) => Promise; + showUploadFilesDialog: () => Promise; + showUploadDirsDialog: () => Promise; + getPendingUploads: () => Promise<{ + files: ElectronFile[]; + collectionName: string; + type: string; + }>; + setToUploadFiles: (type: string, filePaths: string[]) => void; + showUploadZipDialog: () => Promise<{ + zipPaths: string[]; + files: ElectronFile[]; + }>; + getElectronFilesFromGoogleZip: ( + filePath: string + ) => Promise; + setToUploadCollection: (collectionName: string) => void; + getAllFilesFromDir: (dirPath: string) => Promise; + getWatchMappings: () => WatchMapping[]; + setWatchMappings: (watchMappings: WatchMapping[]) => void; + addWatchMapping: ( + collectionName: string, + folderPath: string + ) => Promise; + removeWatchMapping: (collectionName: string) => Promise; + registerWatcherFunctions: ( + WatchServiceInstance: WatchService, + addFile: ( + WatchServiceInstance: WatchService, + file: ElectronFile + ) => Promise, + removeFile: ( + WatchServiceInstance: WatchService, + path: string + ) => Promise, + removeFolder: ( + WatchServiceInstance: WatchService, + folderPath: string + ) => Promise + ) => void; + doesFolderExists: (dirPath: string) => Promise; +} From 1c2491dcbb6241f42a466a4ba970a371a49ae199 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Thu, 9 Jun 2022 20:13:37 +0530 Subject: [PATCH 026/295] redesign modal --- src/components/WatchModal.tsx | 242 ++++++++++++++++------------------ 1 file changed, 110 insertions(+), 132 deletions(-) diff --git a/src/components/WatchModal.tsx b/src/components/WatchModal.tsx index 362175f81c63817765112e2ab1f70ecb52636ad0..ebf8a06a9dcb2d8559b8f79de71673532edec9e8 100644 --- a/src/components/WatchModal.tsx +++ b/src/components/WatchModal.tsx @@ -1,12 +1,75 @@ +/* eslint-disable */ import React, { useEffect, useState } from 'react'; -import { Button, CircularProgress, Dialog, IconButton } from '@mui/material'; +import { + Button, + CircularProgress, + Dialog, + Icon, + IconButton, +} from '@mui/material'; import watchService from 'services/watchService'; import { MdDelete } from 'react-icons/md'; import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; import Close from '@mui/icons-material/Close'; -import { SpaceBetweenFlex } from 'components/Container'; +import { CenteredFlex, SpaceBetweenFlex } from 'components/Container'; import { WatchMapping } from 'types/watch'; import { AppContext } from 'pages/_app'; +import CheckIcon from '@mui/icons-material/Check'; +import FolderIcon from '@mui/icons-material/Folder'; +import { default as MuiStyled } from '@mui/styled-engine'; +import { Box } from '@mui/system'; + +const ModalHeading = MuiStyled('h3')({ + fontSize: '28px', + marginBottom: '24px', + fontWeight: 'bold', +}); + +const FullWidthButton = MuiStyled(Button)({ + width: '100%', + borderRadius: '4px', +}); + +const PaddedContainer = MuiStyled(Box)({ + padding: '24px', +}); + +const FixedHeightContainer = MuiStyled(Box)({ + height: '450px', + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'space-between', +}); + +const VerticallyCentered = MuiStyled(Box)({ + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', +}); + +const NoFoldersTitleText = MuiStyled('h4')({ + fontSize: '24px', + marginBottom: '16px', + fontWeight: 'bold', +}); + +const BottomMarginSpacer = MuiStyled(Box)({ + marginBottom: '10px', +}); + +function CheckmarkIcon() { + return ( + theme.palette.grey.A200, + }}> + + + ); +} function WatchModal({ watchModalView, @@ -55,141 +118,56 @@ function WatchModal({ }; return ( - -
- -
- Watch Folders -
- - - -
-
-
- -
+ + + + Watched folders + - {inputFolderPath} -
-
-
- -
-
- -
- Current Watch Mappings -
- {appContext.watchServiceIsRunning && ( - - + - )} -
-
- {mappings.map((mapping) => ( -
+ + {mappings.length === 0 ? ( + -
- - {mapping.folderPath}{' '} - - - - {mapping.collectionName} - -
-
+ No folders added yet! + + The folders you add here will monitored to + automatically + + + Upload new files to ente + + + Remove deleted files from ente + + + ) : null} + + + + + + - - handleRemoveWatchMapping(mapping) - } - /> -
-
- ))} -
-
+ marginLeft: '8px', + }}> + Add folder + + + +
); } From 3c7eb0797b1a8a5a804d5af436df1389a15630e1 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Fri, 10 Jun 2022 16:01:59 +0530 Subject: [PATCH 027/295] redesigned watch modal --- src/components/WatchModal.tsx | 240 ++++++++++++++++++++++++++++---- src/themes/darkThemeOptions.tsx | 1 + 2 files changed, 215 insertions(+), 26 deletions(-) diff --git a/src/components/WatchModal.tsx b/src/components/WatchModal.tsx index ebf8a06a9dcb2d8559b8f79de71673532edec9e8..fd3c4f3e1f6831fa086238bc2931752f70816ddc 100644 --- a/src/components/WatchModal.tsx +++ b/src/components/WatchModal.tsx @@ -1,4 +1,3 @@ -/* eslint-disable */ import React, { useEffect, useState } from 'react'; import { Button, @@ -6,26 +5,30 @@ import { Dialog, Icon, IconButton, + Menu, + MenuItem, } from '@mui/material'; import watchService from 'services/watchService'; -import { MdDelete } from 'react-icons/md'; -import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; import Close from '@mui/icons-material/Close'; import { CenteredFlex, SpaceBetweenFlex } from 'components/Container'; import { WatchMapping } from 'types/watch'; import { AppContext } from 'pages/_app'; import CheckIcon from '@mui/icons-material/Check'; -import FolderIcon from '@mui/icons-material/Folder'; +import FolderOpenIcon from '@mui/icons-material/FolderOpen'; +import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; +import DoNotDisturbOutlinedIcon from '@mui/icons-material/DoNotDisturbOutlined'; import { default as MuiStyled } from '@mui/styled-engine'; import { Box } from '@mui/system'; +import DialogBox from './DialogBox'; const ModalHeading = MuiStyled('h3')({ fontSize: '28px', marginBottom: '24px', - fontWeight: 'bold', + fontWeight: 600, }); -const FullWidthButton = MuiStyled(Button)({ +const FullWidthButtonWithTopMargin = MuiStyled(Button)({ + marginTop: '16px', width: '100%', borderRadius: '4px', }); @@ -42,22 +45,74 @@ const FixedHeightContainer = MuiStyled(Box)({ alignItems: 'space-between', }); -const VerticallyCentered = MuiStyled(Box)({ +const FullHeightVerticallyCentered = MuiStyled(Box)({ display: 'flex', flexDirection: 'column', - justifyContent: 'center', + height: '100%', + overflowY: 'auto', + margin: 0, + padding: 0, + listStyle: 'none', + '&::-webkit-scrollbar': { + width: '6px', + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: 'slategrey', + }, }); const NoFoldersTitleText = MuiStyled('h4')({ fontSize: '24px', marginBottom: '16px', - fontWeight: 'bold', + fontWeight: 600, }); const BottomMarginSpacer = MuiStyled(Box)({ marginBottom: '10px', }); +const HorizontalFlex = MuiStyled(Box)({ + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-between', +}); + +const VerticalFlex = MuiStyled(Box)({ + display: 'flex', + flexDirection: 'column', +}); + +const MappingEntryTitle = MuiStyled(Box)({ + fontSize: '16px', + fontWeight: 500, + marginLeft: '12px', + marginRight: '6px', +}); + +const MappingEntryFolder = MuiStyled(Box)({ + fontSize: '14px', + fontWeight: 500, + marginTop: '2px', + marginLeft: '12px', + marginRight: '6px', + marginBottom: '6px', + lineHeight: '18px', +}); + +const DialogBoxHeading = MuiStyled('h4')({ + fontSize: '24px', + marginBottom: '16px', + fontWeight: 600, +}); + +const DialogBoxText = MuiStyled('p')({ + fontWeight: 500, +}); + +const DialogBoxButton = MuiStyled(Button)({ + width: '140px', +}); + function CheckmarkIcon() { return ( void; }) { const [mappings, setMappings] = useState([]); - const [inputFolderPath, setInputFolderPath] = useState(''); - const appContext = React.useContext(AppContext); useEffect(() => { setMappings(watchService.getWatchMappings()); }, []); + const handleAddFolderClick = async () => { + await handleFolderSelection(); + }; + const handleFolderSelection = async () => { const folderPath = await watchService.selectFolder(); - setInputFolderPath(folderPath); + await handleAddWatchMapping(folderPath); }; - const handleAddWatchMapping = async () => { - if (inputFolderPath.length > 0) { + const handleAddWatchMapping = async (inputFolderPath: string) => { + if (inputFolderPath?.length > 0) { await watchService.addWatchMapping( inputFolderPath.substring(inputFolderPath.lastIndexOf('/') + 1), inputFolderPath ); - setInputFolderPath(''); setMappings(watchService.getWatchMappings()); } }; @@ -107,11 +163,11 @@ function WatchModal({ setMappings(watchService.getWatchMappings()); }; - const handleSyncProgressClick = () => { - if (watchService.isUploadRunning()) { - watchService.showProgressView(); - } - }; + // const handleSyncProgressClick = () => { + // if (watchService.isUploadRunning()) { + // watchService.showProgressView(); + // } + // }; const handleClose = () => { setWatchModalView(false); @@ -137,9 +193,9 @@ function WatchModal({ {mappings.length === 0 ? ( - No folders added yet! @@ -153,18 +209,34 @@ function WatchModal({ Remove deleted files from ente - - ) : null} + + ) : ( + + {mappings.map((mapping: WatchMapping) => { + return ( + + ); + })} + + )} - + + Add folder - + @@ -172,4 +244,120 @@ function WatchModal({ ); } +function MappingEntry({ + mapping, + handleRemoveMapping, +}: { + mapping: WatchMapping; + handleRemoveMapping: (mapping: WatchMapping) => void; +}) { + const appContext = React.useContext(AppContext); + + useEffect(() => { + console.log(appContext.watchServiceIsRunning); + }, [appContext.watchServiceIsRunning]); + + const [anchorEl, setAnchorEl] = useState(null); + const [dialogBoxOpen, setDialogBoxOpen] = useState(false); + const open = Boolean(anchorEl); + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + const handleClose = () => { + setAnchorEl(null); + }; + + return ( + <> + + + + + + {mapping.collectionName} + {appContext.watchServiceIsRunning && + watchService.currentEvent?.collectionName === + mapping.collectionName && ( + + )} + + theme.palette.grey[500], + }}> + {mapping.folderPath} + + + + + + + + + setDialogBoxOpen(true)} + sx={{ + fontWeight: 600, + color: (theme) => theme.palette.danger.main, + }}> + + + {' '} + Stop watching + + + setDialogBoxOpen(false)} + attributes={{}}> + Stop watching folder? + + Your existing files will not be deleted, but ente will stop + automatically updating the linked ente album on changes in + this folder. + + + setDialogBoxOpen(false)}> + Cancel + + handleRemoveMapping(mapping)}> + Yes, stop + + + + + ); +} + export default WatchModal; diff --git a/src/themes/darkThemeOptions.tsx b/src/themes/darkThemeOptions.tsx index 7b279cbad4c92ebef4e064c35f18abe9ea5b8e21..0689a725218ed031b4c9e10de27bb826eb13bbbd 100644 --- a/src/themes/darkThemeOptions.tsx +++ b/src/themes/darkThemeOptions.tsx @@ -149,6 +149,7 @@ const darkThemeOptions = createTheme({ A100: '#ccc', A200: 'rgba(256, 256, 256, 0.24)', A400: '#434343', + 500: 'rgba(256, 256, 256, 0.5)', }, divider: 'rgba(256, 256, 256, 0.12)', }, From 64988d8fafef4c26c2113cbb6c126fb979f85739 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Sun, 12 Jun 2022 17:28:46 +0530 Subject: [PATCH 028/295] minimize upload progress modal when triggered by watch service --- src/components/UploadProgress/index.tsx | 9 ++++++++- src/components/UploadProgress/minimized.tsx | 6 ++++-- src/components/WatchModal.tsx | 6 ------ src/components/pages/gallery/Upload.tsx | 3 --- src/services/watchService.ts | 4 +--- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/components/UploadProgress/index.tsx b/src/components/UploadProgress/index.tsx index 8996b0c3036c52cf9a9c96d878c99551946090f1..7ff18daf4c61da320b9aeaad5b29956d612dab45 100644 --- a/src/components/UploadProgress/index.tsx +++ b/src/components/UploadProgress/index.tsx @@ -1,6 +1,6 @@ import { UploadProgressDialog } from './dialog'; import { MinimizedUploadProgress } from './minimized'; -import React, { useContext, useState } from 'react'; +import React, { useContext, useEffect, useState } from 'react'; import constants from 'utils/strings/constants'; import { UPLOAD_STAGES } from 'constants/upload'; @@ -13,6 +13,7 @@ import { InProgressUpload, } from 'types/upload/ui'; import UploadProgressContext from 'contexts/uploadProgress'; +import watchService from 'services/watchService'; interface Props { open: boolean; @@ -43,6 +44,12 @@ export default function UploadProgress({ const appContext = useContext(AppContext); const [expanded, setExpanded] = useState(true); + useEffect(() => { + if (appContext.watchServiceIsRunning && watchService.isUploadRunning) { + setExpanded(false); + } + }, [appContext.watchServiceIsRunning]); + function confirmCancelUpload() { appContext.setDialogMessage({ title: constants.STOP_UPLOADS_HEADER, diff --git a/src/components/UploadProgress/minimized.tsx b/src/components/UploadProgress/minimized.tsx index c314dcd98e2e7098835e84259dfd558a6bd0917c..c40995b532c623d4da8f369240a0b7c42f18778b 100644 --- a/src/components/UploadProgress/minimized.tsx +++ b/src/components/UploadProgress/minimized.tsx @@ -1,10 +1,12 @@ import { Snackbar, Paper } from '@mui/material'; -import React from 'react'; +import UploadProgressContext from 'contexts/uploadProgress'; +import React, { useContext } from 'react'; import { UploadProgressHeader } from './header'; export function MinimizedUploadProgress(props) { + const { open } = useContext(UploadProgressContext); return ( { - // if (watchService.isUploadRunning()) { - // watchService.showProgressView(); - // } - // }; - const handleClose = () => { setWatchModalView(false); }; diff --git a/src/components/pages/gallery/Upload.tsx b/src/components/pages/gallery/Upload.tsx index 1f4b131726587f6046c6a9bb94c029dc8f16a6ce..ca1b7661cdf2795b1339d57f29fb025daec1076d 100644 --- a/src/components/pages/gallery/Upload.tsx +++ b/src/components/pages/gallery/Upload.tsx @@ -132,7 +132,6 @@ export default function Upload(props: Props) { props.setElectronFiles, setCollectionName, props.syncWithRemote, - showProgressView, appContext.setWatchServiceIsRunning ); } @@ -143,8 +142,6 @@ export default function Upload(props: Props) { pendingDesktopUploadCollectionName.current = collectionName; }; - const showProgressView = () => {}; - useEffect(() => { if ( props.electronFiles?.length > 0 || diff --git a/src/services/watchService.ts b/src/services/watchService.ts index 7b5cd5775953ef7e28563940ea2bd71b6700e077..e108b245e401c63c210b05931e8eb60a98700ba4 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -38,7 +38,6 @@ export class WatchService { setElectronFiles: (files: ElectronFile[]) => void, setCollectionName: (collectionName: string) => void, syncWithRemote: () => void, - showProgressView: () => void, setWatchServiceIsRunning: (isRunning: boolean) => void ) { if (this.allElectronAPIsExist) { @@ -46,7 +45,6 @@ export class WatchService { this.setElectronFiles = setElectronFiles; this.setCollectionName = setCollectionName; this.syncWithRemote = syncWithRemote; - this.showProgressView = showProgressView; this.setWatchServiceIsRunning = setWatchServiceIsRunning; let mappings = this.getWatchMappings(); @@ -409,7 +407,7 @@ export class WatchService { const mappings = this.getWatchMappings(); const collectionName = mappings.find((mapping) => - filePath.startsWith(mapping.folderPath) + filePath.startsWith(mapping.folderPath + '/') )?.collectionName; if (!collectionName) { From 2ed3b457862cb68c1aa92ab101f884a79e8ee896 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Sun, 12 Jun 2022 18:49:29 +0530 Subject: [PATCH 029/295] added functionality to drag and drop folder to create watch mapping --- src/components/WatchModal.tsx | 45 ++++++++++++++++++++++++++++++++++- src/pages/gallery/index.tsx | 10 +++++++- src/services/watchService.ts | 11 +++++++++ src/types/gallery/index.ts | 1 + 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/components/WatchModal.tsx b/src/components/WatchModal.tsx index a6d9935674e1fc414e251162c0a07677635791c8..7666f041ebb87b6a5237fd1bd04f6e90d1288ce0 100644 --- a/src/components/WatchModal.tsx +++ b/src/components/WatchModal.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useContext, useEffect, useState } from 'react'; import { Button, CircularProgress, @@ -20,6 +20,7 @@ import DoNotDisturbOutlinedIcon from '@mui/icons-material/DoNotDisturbOutlined'; import { default as MuiStyled } from '@mui/styled-engine'; import { Box } from '@mui/system'; import DialogBox from './DialogBox'; +import { GalleryContext } from 'pages/gallery'; const ModalHeading = MuiStyled('h3')({ fontSize: '28px', @@ -134,11 +135,53 @@ function WatchModal({ setWatchModalView: (watchModalView: boolean) => void; }) { const [mappings, setMappings] = useState([]); + const { setDropZoneActive } = useContext(GalleryContext); useEffect(() => { setMappings(watchService.getWatchMappings()); }, []); + useEffect(() => { + if (watchModalView) { + setDropZoneActive(false); + + const handleDrag = (e: DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + }; + const handleDrop = (e: DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + + const files = e.dataTransfer.files; + if (files.length > 0) { + handleFolderDrop(files); + } + }; + addEventListener('dragover', handleDrag); + addEventListener('drop', handleDrop); + + return () => { + setDropZoneActive(true); + removeEventListener('dragover', handleDrag); + removeEventListener('drop', handleDrop); + }; + } + }, [watchModalView]); + + const handleFolderDrop = async (folders: FileList) => { + if (folders.length === 0) { + return; + } + for (let i = 0; i < folders.length; i++) { + const folder: any = folders[i]; + const path = (folder.path as string).replace(/\\/g, '/'); + if (await watchService.isFolder(path)) { + await handleAddWatchMapping(path); + } + } + }; + const handleAddFolderClick = async () => { await handleFolderSelection(); }; diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index 07807d5c6df20c51a9356c6254832dd57b8788da..e8270f90b67aa5db4f7dac12e0c5ea001d1084f2 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -126,6 +126,7 @@ const defaultGalleryContext: GalleryContextType = { syncWithRemote: () => null, setNotificationAttributes: () => null, setBlockingLoad: () => null, + setDropZoneActive: () => null, }; export const GalleryContext = createContext( @@ -155,6 +156,8 @@ export default function Gallery() { const [collectionNamerView, setCollectionNamerView] = useState(false); const [search, setSearch] = useState(null); const [uploadInProgress, setUploadInProgress] = useState(false); + const [dropZoneDisabled, setDropZoneDisabled] = useState(false); + const { getRootProps, getInputProps, @@ -164,7 +167,7 @@ export default function Gallery() { } = useDropzone({ noClick: true, noKeyboard: true, - disabled: uploadInProgress, + disabled: uploadInProgress || dropZoneDisabled, }); const [isInSearchMode, setIsInSearchMode] = useState(false); @@ -561,6 +564,10 @@ export default function Gallery() { finishLoading(); }; + const setDropZoneActive = (active: boolean) => { + setDropZoneDisabled(!active); + }; + const openUploader = () => { if (importService.checkAllElectronAPIsExists()) { setUploadTypeSelectorView(true); @@ -578,6 +585,7 @@ export default function Gallery() { syncWithRemote, setNotificationAttributes, setBlockingLoad, + setDropZoneActive, }}> Promise; setNotificationAttributes: (attributes: NotificationAttributes) => void; setBlockingLoad: (value: boolean) => void; + setDropZoneActive: (value: boolean) => void; }; From e14aba2d6f9aff542c1e509984a838261281b5d6 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Sun, 12 Jun 2022 23:52:37 +0530 Subject: [PATCH 030/295] moved strings to string constants --- src/components/WatchModal.tsx | 30 ++++++++++++++------------ src/utils/strings/englishConstants.tsx | 12 +++++++++++ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/components/WatchModal.tsx b/src/components/WatchModal.tsx index 7666f041ebb87b6a5237fd1bd04f6e90d1288ce0..7b067b2f382b0c6d74578c5c20b66cdee7406277 100644 --- a/src/components/WatchModal.tsx +++ b/src/components/WatchModal.tsx @@ -21,6 +21,7 @@ import { default as MuiStyled } from '@mui/styled-engine'; import { Box } from '@mui/system'; import DialogBox from './DialogBox'; import { GalleryContext } from 'pages/gallery'; +import constants from 'utils/strings/constants'; const ModalHeading = MuiStyled('h3')({ fontSize: '28px', @@ -219,7 +220,7 @@ function WatchModal({ - Watched folders + {constants.WATCHED_FOLDERS} - No folders added yet! + {constants.NO_FOLDERS_ADDED} - The folders you add here will monitored to - automatically + {constants.FOLDERS_AUTOMATICALLY_MONITORED} - Upload new files to ente + {' '} + {constants.UPLOAD_NEW_FILES_TO_ENTE} - Remove deleted files from ente + {' '} + {constants.REMOVE_DELETED_FILES_FROM_ENTE} ) : ( @@ -272,7 +274,7 @@ function WatchModal({ style={{ marginLeft: '8px', }}> - Add folder + {constants.ADD_FOLDER} @@ -363,7 +365,7 @@ function MappingEntry({ }}> {' '} - Stop watching + {constants.STOP_WATCHING} setDialogBoxOpen(false)} attributes={{}}> - Stop watching folder? + + {constants.STOP_WATCHING_FOLDER} + - Your existing files will not be deleted, but ente will stop - automatically updating the linked ente album on changes in - this folder. + {constants.STOP_WATCHING_DIALOG_MESSAGE} setDialogBoxOpen(false)}> - Cancel + {constants.CANCEL} handleRemoveMapping(mapping)}> - Yes, stop + {constants.YES_STOP} diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx index 5b0038bf8e3d6a090749449dbdd60fefa5dd573d..797591b296be1fa0ec61e4d87f818f0f6b6da3d8 100644 --- a/src/utils/strings/englishConstants.tsx +++ b/src/utils/strings/englishConstants.tsx @@ -772,6 +772,18 @@ const englishConstants = { FAMILY: 'Family', FREE: 'free', OF: 'of', + WATCHED_FOLDERS: 'Watched Folders', + NO_FOLDERS_ADDED: 'No folders added yet!', + FOLDERS_AUTOMATICALLY_MONITORED: + 'The folders you add here will monitored to automatically', + UPLOAD_NEW_FILES_TO_ENTE: 'Upload new files to ente', + REMOVE_DELETED_FILES_FROM_ENTE: 'Remove deleted files from ente', + ADD_FOLDER: 'Add folder', + STOP_WATCHING: 'Stop watching', + STOP_WATCHING_FOLDER: 'Stop watching folder?', + STOP_WATCHING_DIALOG_MESSAGE: + 'Your existing files will not be deleted, but ente will stop automatically updating the linked ente album on changes in this folder.', + YES_STOP: 'Yes, stop', }; export default englishConstants; From accf97c38b566985d2d023fdafeb0b045f8924bd Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Mon, 13 Jun 2022 12:05:34 +0530 Subject: [PATCH 031/295] redundant check --- src/components/WatchModal.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/WatchModal.tsx b/src/components/WatchModal.tsx index 7b067b2f382b0c6d74578c5c20b66cdee7406277..4e167b1fb63b582ee9929662ba8e73fc8ec1c1b0 100644 --- a/src/components/WatchModal.tsx +++ b/src/components/WatchModal.tsx @@ -171,9 +171,6 @@ function WatchModal({ }, [watchModalView]); const handleFolderDrop = async (folders: FileList) => { - if (folders.length === 0) { - return; - } for (let i = 0; i < folders.length; i++) { const folder: any = folders[i]; const path = (folder.path as string).replace(/\\/g, '/'); From 21c5af67525ca7ae295809514420879fcc3206a0 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Mon, 13 Jun 2022 12:23:15 +0530 Subject: [PATCH 032/295] check if on the web --- src/components/Sidebar/UtilitySection.tsx | 22 +++++++++++++++++++++- src/utils/strings/englishConstants.tsx | 2 +- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/components/Sidebar/UtilitySection.tsx b/src/components/Sidebar/UtilitySection.tsx index ee9c2b59048c0a3cae3e8db76cd67cdb484b38aa..180b054a6ee05b9265203cbf2d8fb670e57e00b1 100644 --- a/src/components/Sidebar/UtilitySection.tsx +++ b/src/components/Sidebar/UtilitySection.tsx @@ -8,6 +8,8 @@ import { PAGES } from 'constants/pages'; import { useRouter } from 'next/router'; import { AppContext } from 'pages/_app'; import WatchModal from '../WatchModal'; +import isElectron from 'is-electron'; +import { downloadApp } from 'utils/common'; export default function UtilitySection({ closeSidebar }) { const router = useRouter(); @@ -24,7 +26,25 @@ export default function UtilitySection({ closeSidebar }) { const openTwoFactorModalView = () => setTwoFactorModalView(true); const closeTwoFactorModalView = () => setTwoFactorModalView(false); - const openWatchModalView = () => setWatchModalView(true); + const openWatchModalView = () => { + if (isElectron()) { + setWatchModalView(true); + } else { + setDialogMessage({ + title: constants.DOWNLOAD_APP, + content: constants.DOWNLOAD_APP_MESSAGE(), + + proceed: { + text: constants.DOWNLOAD, + action: downloadApp, + variant: 'success', + }, + close: { + text: constants.CLOSE, + }, + }); + } + }; const redirectToChangePasswordPage = () => { closeSidebar(); diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx index 797591b296be1fa0ec61e4d87f818f0f6b6da3d8..5d4d85f9032e91cba8505761ed4ad8df0663c991 100644 --- a/src/utils/strings/englishConstants.tsx +++ b/src/utils/strings/englishConstants.tsx @@ -237,7 +237,7 @@ const englishConstants = { DOWNLOAD_APP_MESSAGE: () => ( <>

- Sorry, this operation is currently only supported on our desktop + Sorry, this feature is currently only supported on our desktop app

From 88a1039419fbf42ca01b68e97405fe938844c188 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 15 Jun 2022 13:58:07 +0530 Subject: [PATCH 033/295] use accent instead of success --- src/components/Sidebar/UtilitySection.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Sidebar/UtilitySection.tsx b/src/components/Sidebar/UtilitySection.tsx index 180b054a6ee05b9265203cbf2d8fb670e57e00b1..ba184e4f2ad51f0b4880b774855c19498252ecd0 100644 --- a/src/components/Sidebar/UtilitySection.tsx +++ b/src/components/Sidebar/UtilitySection.tsx @@ -37,7 +37,7 @@ export default function UtilitySection({ closeSidebar }) { proceed: { text: constants.DOWNLOAD, action: downloadApp, - variant: 'success', + variant: 'accent', }, close: { text: constants.CLOSE, From 31cccabaccb5c5b11582e7eefa4059e9ca272b6f Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 15 Jun 2022 14:00:49 +0530 Subject: [PATCH 034/295] fix using invalid prop --- src/components/UploadProgress/minimized.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/UploadProgress/minimized.tsx b/src/components/UploadProgress/minimized.tsx index c40995b532c623d4da8f369240a0b7c42f18778b..db33986774d999a75c71c8072611d784d6f45c07 100644 --- a/src/components/UploadProgress/minimized.tsx +++ b/src/components/UploadProgress/minimized.tsx @@ -2,11 +2,11 @@ import { Snackbar, Paper } from '@mui/material'; import UploadProgressContext from 'contexts/uploadProgress'; import React, { useContext } from 'react'; import { UploadProgressHeader } from './header'; -export function MinimizedUploadProgress(props) { +export function MinimizedUploadProgress() { const { open } = useContext(UploadProgressContext); return ( Date: Wed, 15 Jun 2022 14:26:32 +0530 Subject: [PATCH 035/295] refactor watchModalComponent --- src/components/Sidebar/UtilitySection.tsx | 13 +- src/components/WatchFolder/checkmarkIcon.tsx | 16 + src/components/WatchFolder/index.tsx | 162 +++++++ src/components/WatchFolder/mappingEntry.tsx | 136 ++++++ .../WatchFolder/styledComponents.tsx | 81 ++++ src/components/WatchModal.tsx | 399 ------------------ 6 files changed, 402 insertions(+), 405 deletions(-) create mode 100644 src/components/WatchFolder/checkmarkIcon.tsx create mode 100644 src/components/WatchFolder/index.tsx create mode 100644 src/components/WatchFolder/mappingEntry.tsx create mode 100644 src/components/WatchFolder/styledComponents.tsx delete mode 100644 src/components/WatchModal.tsx diff --git a/src/components/Sidebar/UtilitySection.tsx b/src/components/Sidebar/UtilitySection.tsx index ba184e4f2ad51f0b4880b774855c19498252ecd0..30487da6b445c4a072b697b1d666d8a25aa04204 100644 --- a/src/components/Sidebar/UtilitySection.tsx +++ b/src/components/Sidebar/UtilitySection.tsx @@ -7,9 +7,9 @@ import TwoFactorModal from 'components/TwoFactor/Modal'; import { PAGES } from 'constants/pages'; import { useRouter } from 'next/router'; import { AppContext } from 'pages/_app'; -import WatchModal from '../WatchModal'; import isElectron from 'is-electron'; import { downloadApp } from 'utils/common'; +import WatchFolderModal from 'components/WatchFolder'; export default function UtilitySection({ closeSidebar }) { const router = useRouter(); @@ -17,7 +17,7 @@ export default function UtilitySection({ closeSidebar }) { const [recoverModalView, setRecoveryModalView] = useState(false); const [twoFactorModalView, setTwoFactorModalView] = useState(false); - const [watchModalView, setWatchModalView] = useState(false); + const [watchFolderModalView, setWatchFolderModalView] = useState(false); // const [fixLargeThumbsView, setFixLargeThumbsView] = useState(false); const openRecoveryKeyModal = () => setRecoveryModalView(true); @@ -28,7 +28,7 @@ export default function UtilitySection({ closeSidebar }) { const openWatchModalView = () => { if (isElectron()) { - setWatchModalView(true); + setWatchFolderModalView(true); } else { setDialogMessage({ title: constants.DOWNLOAD_APP, @@ -67,6 +67,7 @@ export default function UtilitySection({ closeSidebar }) { close: { variant: 'danger' }, }); + const closeWatchFolderModal = () => setWatchFolderModalView(false); return ( <> @@ -103,9 +104,9 @@ export default function UtilitySection({ closeSidebar }) { closeSidebar={closeSidebar} setLoading={startLoading} /> - {/* theme.palette.grey.A200, + }}> + +
+ ); +} diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2007a20a2c123baa4e0140394128da9323f2cd89 --- /dev/null +++ b/src/components/WatchFolder/index.tsx @@ -0,0 +1,162 @@ +import { + BottomMarginSpacer, + FixedHeightContainer, + FullHeightVerticallyCentered, + FullWidthButtonWithTopMargin, + ModalHeading, + NoFoldersTitleText, + PaddedContainer, +} from './styledComponents'; +import React, { useContext, useEffect, useState } from 'react'; +import { Dialog, IconButton } from '@mui/material'; +import watchService from 'services/watchService'; +import Close from '@mui/icons-material/Close'; +import { CenteredFlex, SpaceBetweenFlex } from 'components/Container'; +import { WatchMapping } from 'types/watch'; +import { GalleryContext } from 'pages/gallery'; +import constants from 'utils/strings/constants'; +import { CheckmarkIcon } from './checkmarkIcon'; +import { MappingEntry } from './mappingEntry'; + +interface NewType { + open: boolean; + onClose: () => void; +} + +export default function WatchFolderModal({ open, onClose }: NewType) { + const [mappings, setMappings] = useState([]); + const { setDropZoneActive } = useContext(GalleryContext); + + useEffect(() => { + setMappings(watchService.getWatchMappings()); + }, []); + + useEffect(() => { + if (open) { + setDropZoneActive(false); + + const handleDrag = (e: DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + }; + const handleDrop = (e: DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + + const files = e.dataTransfer.files; + if (files.length > 0) { + handleFolderDrop(files); + } + }; + addEventListener('dragover', handleDrag); + addEventListener('drop', handleDrop); + + return () => { + setDropZoneActive(true); + removeEventListener('dragover', handleDrag); + removeEventListener('drop', handleDrop); + }; + } + }, [open]); + + const handleFolderDrop = async (folders: FileList) => { + for (let i = 0; i < folders.length; i++) { + const folder: any = folders[i]; + const path = (folder.path as string).replace(/\\/g, '/'); + if (await watchService.isFolder(path)) { + await handleAddWatchMapping(path); + } + } + }; + + const handleAddFolderClick = async () => { + await handleFolderSelection(); + }; + + const handleFolderSelection = async () => { + const folderPath = await watchService.selectFolder(); + await handleAddWatchMapping(folderPath); + }; + + const handleAddWatchMapping = async (inputFolderPath: string) => { + if (inputFolderPath?.length > 0) { + await watchService.addWatchMapping( + inputFolderPath.substring(inputFolderPath.lastIndexOf('/') + 1), + inputFolderPath + ); + setMappings(watchService.getWatchMappings()); + } + }; + + const handleRemoveWatchMapping = async (mapping: WatchMapping) => { + await watchService.removeWatchMapping(mapping.collectionName); + setMappings(watchService.getWatchMappings()); + }; + + return ( + + + + + {constants.WATCHED_FOLDERS} + + + + + + {mappings.length === 0 ? ( + + + {constants.NO_FOLDERS_ADDED} + + {constants.FOLDERS_AUTOMATICALLY_MONITORED} + + + {' '} + {constants.UPLOAD_NEW_FILES_TO_ENTE} + + + {' '} + {constants.REMOVE_DELETED_FILES_FROM_ENTE} + + + ) : ( + + {mappings.map((mapping: WatchMapping) => { + return ( + + ); + })} + + )} + + + + + + + {constants.ADD_FOLDER} + + + + + + ); +} diff --git a/src/components/WatchFolder/mappingEntry.tsx b/src/components/WatchFolder/mappingEntry.tsx new file mode 100644 index 0000000000000000000000000000000000000000..976e6009bbf9f8c0d3fcdb6d012a9df843b24b2b --- /dev/null +++ b/src/components/WatchFolder/mappingEntry.tsx @@ -0,0 +1,136 @@ +import { + DialogBoxButton, + DialogBoxHeading, + DialogBoxText, + HorizontalFlex, + MappingEntryFolder, + MappingEntryTitle, + VerticalFlex, +} from './styledComponents'; +import React, { useEffect, useState } from 'react'; +import { CircularProgress, IconButton, Menu, MenuItem } from '@mui/material'; +import watchService from 'services/watchService'; +import { SpaceBetweenFlex } from 'components/Container'; +import { WatchMapping } from 'types/watch'; +import { AppContext } from 'pages/_app'; +import FolderOpenIcon from '@mui/icons-material/FolderOpen'; +import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; +import DoNotDisturbOutlinedIcon from '@mui/icons-material/DoNotDisturbOutlined'; +import DialogBox from '../DialogBox'; +import constants from 'utils/strings/constants'; + +export function MappingEntry({ + mapping, + handleRemoveMapping, +}: { + mapping: WatchMapping; + handleRemoveMapping: (mapping: WatchMapping) => void; +}) { + const appContext = React.useContext(AppContext); + + useEffect(() => { + console.log(appContext.watchServiceIsRunning); + }, [appContext.watchServiceIsRunning]); + + const [anchorEl, setAnchorEl] = useState(null); + const [dialogBoxOpen, setDialogBoxOpen] = useState(false); + const open = Boolean(anchorEl); + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + const handleClose = () => { + setAnchorEl(null); + }; + + return ( + <> + + + + + + {mapping.collectionName} + {appContext.watchServiceIsRunning && + watchService.currentEvent?.collectionName === + mapping.collectionName && ( + + )} + + theme.palette.grey[500], + }}> + {mapping.folderPath} + + + + + + + + + setDialogBoxOpen(true)} + sx={{ + fontWeight: 600, + color: (theme) => theme.palette.danger.main, + }}> + + + {' '} + {constants.STOP_WATCHING} + + + setDialogBoxOpen(false)} + attributes={{}}> + + {constants.STOP_WATCHING_FOLDER} + + + {constants.STOP_WATCHING_DIALOG_MESSAGE} + + + setDialogBoxOpen(false)}> + {constants.CANCEL} + + handleRemoveMapping(mapping)}> + {constants.YES_STOP} + + + + + ); +} diff --git a/src/components/WatchFolder/styledComponents.tsx b/src/components/WatchFolder/styledComponents.tsx new file mode 100644 index 0000000000000000000000000000000000000000..20ca60e1f5abbf3efc2dcd1e4dceffa67aed6567 --- /dev/null +++ b/src/components/WatchFolder/styledComponents.tsx @@ -0,0 +1,81 @@ +import { Box, Button } from '@mui/material'; +import { styled } from '@mui/material/styles'; + +export const ModalHeading = styled('h3')({ + fontSize: '28px', + marginBottom: '24px', + fontWeight: 600, +}); +export const FullWidthButtonWithTopMargin = styled(Button)({ + marginTop: '16px', + width: '100%', + borderRadius: '4px', +}); +export const PaddedContainer = styled(Box)({ + padding: '24px', +}); +export const FixedHeightContainer = styled(Box)({ + height: '450px', + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'space-between', +}); +export const FullHeightVerticallyCentered = styled(Box)({ + display: 'flex', + flexDirection: 'column', + height: '100%', + overflowY: 'auto', + margin: 0, + padding: 0, + listStyle: 'none', + '&::-webkit-scrollbar': { + width: '6px', + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: 'slategrey', + }, +}); +export const NoFoldersTitleText = styled('h4')({ + fontSize: '24px', + marginBottom: '16px', + fontWeight: 600, +}); +export const BottomMarginSpacer = styled(Box)({ + marginBottom: '10px', +}); +export const HorizontalFlex = styled(Box)({ + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-between', +}); +export const VerticalFlex = styled(Box)({ + display: 'flex', + flexDirection: 'column', +}); +export const MappingEntryTitle = styled(Box)({ + fontSize: '16px', + fontWeight: 500, + marginLeft: '12px', + marginRight: '6px', +}); +export const MappingEntryFolder = styled(Box)({ + fontSize: '14px', + fontWeight: 500, + marginTop: '2px', + marginLeft: '12px', + marginRight: '6px', + marginBottom: '6px', + lineHeight: '18px', +}); +export const DialogBoxHeading = styled('h4')({ + fontSize: '24px', + marginBottom: '16px', + fontWeight: 600, +}); +export const DialogBoxText = styled('p')({ + fontWeight: 500, +}); +export const DialogBoxButton = styled(Button)({ + width: '140px', +}); diff --git a/src/components/WatchModal.tsx b/src/components/WatchModal.tsx deleted file mode 100644 index 4e167b1fb63b582ee9929662ba8e73fc8ec1c1b0..0000000000000000000000000000000000000000 --- a/src/components/WatchModal.tsx +++ /dev/null @@ -1,399 +0,0 @@ -import React, { useContext, useEffect, useState } from 'react'; -import { - Button, - CircularProgress, - Dialog, - Icon, - IconButton, - Menu, - MenuItem, -} from '@mui/material'; -import watchService from 'services/watchService'; -import Close from '@mui/icons-material/Close'; -import { CenteredFlex, SpaceBetweenFlex } from 'components/Container'; -import { WatchMapping } from 'types/watch'; -import { AppContext } from 'pages/_app'; -import CheckIcon from '@mui/icons-material/Check'; -import FolderOpenIcon from '@mui/icons-material/FolderOpen'; -import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; -import DoNotDisturbOutlinedIcon from '@mui/icons-material/DoNotDisturbOutlined'; -import { default as MuiStyled } from '@mui/styled-engine'; -import { Box } from '@mui/system'; -import DialogBox from './DialogBox'; -import { GalleryContext } from 'pages/gallery'; -import constants from 'utils/strings/constants'; - -const ModalHeading = MuiStyled('h3')({ - fontSize: '28px', - marginBottom: '24px', - fontWeight: 600, -}); - -const FullWidthButtonWithTopMargin = MuiStyled(Button)({ - marginTop: '16px', - width: '100%', - borderRadius: '4px', -}); - -const PaddedContainer = MuiStyled(Box)({ - padding: '24px', -}); - -const FixedHeightContainer = MuiStyled(Box)({ - height: '450px', - display: 'flex', - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'space-between', -}); - -const FullHeightVerticallyCentered = MuiStyled(Box)({ - display: 'flex', - flexDirection: 'column', - height: '100%', - overflowY: 'auto', - margin: 0, - padding: 0, - listStyle: 'none', - '&::-webkit-scrollbar': { - width: '6px', - }, - '&::-webkit-scrollbar-thumb': { - backgroundColor: 'slategrey', - }, -}); - -const NoFoldersTitleText = MuiStyled('h4')({ - fontSize: '24px', - marginBottom: '16px', - fontWeight: 600, -}); - -const BottomMarginSpacer = MuiStyled(Box)({ - marginBottom: '10px', -}); - -const HorizontalFlex = MuiStyled(Box)({ - display: 'flex', - flexDirection: 'row', - justifyContent: 'space-between', -}); - -const VerticalFlex = MuiStyled(Box)({ - display: 'flex', - flexDirection: 'column', -}); - -const MappingEntryTitle = MuiStyled(Box)({ - fontSize: '16px', - fontWeight: 500, - marginLeft: '12px', - marginRight: '6px', -}); - -const MappingEntryFolder = MuiStyled(Box)({ - fontSize: '14px', - fontWeight: 500, - marginTop: '2px', - marginLeft: '12px', - marginRight: '6px', - marginBottom: '6px', - lineHeight: '18px', -}); - -const DialogBoxHeading = MuiStyled('h4')({ - fontSize: '24px', - marginBottom: '16px', - fontWeight: 600, -}); - -const DialogBoxText = MuiStyled('p')({ - fontWeight: 500, -}); - -const DialogBoxButton = MuiStyled(Button)({ - width: '140px', -}); - -function CheckmarkIcon() { - return ( - theme.palette.grey.A200, - }}> - - - ); -} - -function WatchModal({ - watchModalView, - setWatchModalView, -}: { - watchModalView: boolean; - setWatchModalView: (watchModalView: boolean) => void; -}) { - const [mappings, setMappings] = useState([]); - const { setDropZoneActive } = useContext(GalleryContext); - - useEffect(() => { - setMappings(watchService.getWatchMappings()); - }, []); - - useEffect(() => { - if (watchModalView) { - setDropZoneActive(false); - - const handleDrag = (e: DragEvent) => { - e.preventDefault(); - e.stopPropagation(); - }; - const handleDrop = (e: DragEvent) => { - e.preventDefault(); - e.stopPropagation(); - - const files = e.dataTransfer.files; - if (files.length > 0) { - handleFolderDrop(files); - } - }; - addEventListener('dragover', handleDrag); - addEventListener('drop', handleDrop); - - return () => { - setDropZoneActive(true); - removeEventListener('dragover', handleDrag); - removeEventListener('drop', handleDrop); - }; - } - }, [watchModalView]); - - const handleFolderDrop = async (folders: FileList) => { - for (let i = 0; i < folders.length; i++) { - const folder: any = folders[i]; - const path = (folder.path as string).replace(/\\/g, '/'); - if (await watchService.isFolder(path)) { - await handleAddWatchMapping(path); - } - } - }; - - const handleAddFolderClick = async () => { - await handleFolderSelection(); - }; - - const handleFolderSelection = async () => { - const folderPath = await watchService.selectFolder(); - await handleAddWatchMapping(folderPath); - }; - - const handleAddWatchMapping = async (inputFolderPath: string) => { - if (inputFolderPath?.length > 0) { - await watchService.addWatchMapping( - inputFolderPath.substring(inputFolderPath.lastIndexOf('/') + 1), - inputFolderPath - ); - setMappings(watchService.getWatchMappings()); - } - }; - - const handleRemoveWatchMapping = async (mapping: WatchMapping) => { - await watchService.removeWatchMapping(mapping.collectionName); - setMappings(watchService.getWatchMappings()); - }; - - const handleClose = () => { - setWatchModalView(false); - }; - - return ( - - - - - {constants.WATCHED_FOLDERS} - - - - - - {mappings.length === 0 ? ( - - - {constants.NO_FOLDERS_ADDED} - - {constants.FOLDERS_AUTOMATICALLY_MONITORED} - - - {' '} - {constants.UPLOAD_NEW_FILES_TO_ENTE} - - - {' '} - {constants.REMOVE_DELETED_FILES_FROM_ENTE} - - - ) : ( - - {mappings.map((mapping: WatchMapping) => { - return ( - - ); - })} - - )} - - - - + - - {constants.ADD_FOLDER} - - - - - - ); -} - -function MappingEntry({ - mapping, - handleRemoveMapping, -}: { - mapping: WatchMapping; - handleRemoveMapping: (mapping: WatchMapping) => void; -}) { - const appContext = React.useContext(AppContext); - - useEffect(() => { - console.log(appContext.watchServiceIsRunning); - }, [appContext.watchServiceIsRunning]); - - const [anchorEl, setAnchorEl] = useState(null); - const [dialogBoxOpen, setDialogBoxOpen] = useState(false); - const open = Boolean(anchorEl); - const handleClick = (event: React.MouseEvent) => { - setAnchorEl(event.currentTarget); - }; - const handleClose = () => { - setAnchorEl(null); - }; - - return ( - <> - - - - - - {mapping.collectionName} - {appContext.watchServiceIsRunning && - watchService.currentEvent?.collectionName === - mapping.collectionName && ( - - )} - - theme.palette.grey[500], - }}> - {mapping.folderPath} - - - - - - - - - setDialogBoxOpen(true)} - sx={{ - fontWeight: 600, - color: (theme) => theme.palette.danger.main, - }}> - - - {' '} - {constants.STOP_WATCHING} - - - setDialogBoxOpen(false)} - attributes={{}}> - - {constants.STOP_WATCHING_FOLDER} - - - {constants.STOP_WATCHING_DIALOG_MESSAGE} - - - setDialogBoxOpen(false)}> - {constants.CANCEL} - - handleRemoveMapping(mapping)}> - {constants.YES_STOP} - - - - - ); -} - -export default WatchModal; From bf21d8391a2ee0deab4877684b64301c92cd0259 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 15 Jun 2022 14:29:17 +0530 Subject: [PATCH 036/295] update watch type --- src/services/watchService.ts | 16 ++++++++-------- src/types/watch/index.ts | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/services/watchService.ts b/src/services/watchService.ts index 225a49d50e6e6c5da4af24a68c9cf735cc3ec972..7b4d9ed366dca7028480121d701d7f473e5a70ae 100644 --- a/src/services/watchService.ts +++ b/src/services/watchService.ts @@ -6,14 +6,14 @@ import { removeFromCollection, syncCollections } from './collectionService'; import { syncFiles } from './fileService'; import debounce from 'debounce-promise'; import { logError } from 'utils/sentry'; -import { EventQueueType, WatchMapping } from 'types/watch'; +import { EventQueueItem, WatchMapping } from 'types/watch'; import { ElectronAPIsInterface } from 'types/electron'; export class WatchService { ElectronAPIs: ElectronAPIsInterface; allElectronAPIsExist: boolean = false; - eventQueue: EventQueueType[] = []; - currentEvent: EventQueueType; + eventQueue: EventQueueItem[] = []; + currentEvent: EventQueueItem; trashingDirQueue: string[] = []; isEventRunning: boolean = false; uploadRunning: boolean = false; @@ -86,7 +86,7 @@ export class WatchService { }); if (filesToUpload.length > 0) { - const event: EventQueueType = { + const event: EventQueueItem = { type: 'upload', collectionName: mapping.collectionName, files: filesToUpload, @@ -106,7 +106,7 @@ export class WatchService { }); if (filesToRemove.length > 0) { - const event: EventQueueType = { + const event: EventQueueItem = { type: 'trash', collectionName: mapping.collectionName, paths: filesToRemove.map((file) => file.path), @@ -431,7 +431,7 @@ export class WatchService { // Batches all the files to be uploaded (or trashed) from the // event queue of same collection as the next event - private clubSameCollectionEvents(): EventQueueType { + private clubSameCollectionEvents(): EventQueueItem { const event = this.eventQueue.shift(); while ( this.eventQueue.length > 0 && @@ -469,7 +469,7 @@ async function diskFileAddedCallback( console.log('added (upload) to event queue', collectionName, file); - const event: EventQueueType = { + const event: EventQueueItem = { type: 'upload', collectionName, files: [file], @@ -494,7 +494,7 @@ async function diskFileRemovedCallback( return; } - const event: EventQueueType = { + const event: EventQueueItem = { type: 'trash', collectionName, paths: [filePath], diff --git a/src/types/watch/index.ts b/src/types/watch/index.ts index b34594e359e13de20db5f2de61c4043015708685..fdd29e4d9cdd29ddf2c5a50579a3d3805ad2c954 100644 --- a/src/types/watch/index.ts +++ b/src/types/watch/index.ts @@ -9,7 +9,7 @@ export interface WatchMapping { }[]; } -export interface EventQueueType { +export interface EventQueueItem { type: 'upload' | 'trash'; collectionName: string; paths?: string[]; From 42c19b39a16d71a302e88ba680deb415b23882ac Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 15 Jun 2022 14:30:31 +0530 Subject: [PATCH 037/295] rename to watchFolder --- src/components/UploadProgress/index.tsx | 2 +- src/components/WatchFolder/index.tsx | 4 ++-- src/components/WatchFolder/mappingEntry.tsx | 4 ++-- src/components/pages/gallery/Upload.tsx | 2 +- src/services/upload/uploadManager.ts | 2 +- src/services/{watchService.ts => watchFolderService.ts} | 2 +- src/types/electron/index.ts | 4 ++-- src/types/{watch => watchFolder}/index.ts | 0 8 files changed, 10 insertions(+), 10 deletions(-) rename src/services/{watchService.ts => watchFolderService.ts} (99%) rename src/types/{watch => watchFolder}/index.ts (100%) diff --git a/src/components/UploadProgress/index.tsx b/src/components/UploadProgress/index.tsx index 7ff18daf4c61da320b9aeaad5b29956d612dab45..293b6fb4b9aa8b4de9ef3ccac18c80ea6a04eafc 100644 --- a/src/components/UploadProgress/index.tsx +++ b/src/components/UploadProgress/index.tsx @@ -13,7 +13,7 @@ import { InProgressUpload, } from 'types/upload/ui'; import UploadProgressContext from 'contexts/uploadProgress'; -import watchService from 'services/watchService'; +import watchService from 'services/watchFolderService'; interface Props { open: boolean; diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index 2007a20a2c123baa4e0140394128da9323f2cd89..fda40136b736c409554a527d871ef9645f47fbc7 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -9,10 +9,10 @@ import { } from './styledComponents'; import React, { useContext, useEffect, useState } from 'react'; import { Dialog, IconButton } from '@mui/material'; -import watchService from 'services/watchService'; +import watchService from 'services/watchFolderService'; import Close from '@mui/icons-material/Close'; import { CenteredFlex, SpaceBetweenFlex } from 'components/Container'; -import { WatchMapping } from 'types/watch'; +import { WatchMapping } from 'types/watchFolder'; import { GalleryContext } from 'pages/gallery'; import constants from 'utils/strings/constants'; import { CheckmarkIcon } from './checkmarkIcon'; diff --git a/src/components/WatchFolder/mappingEntry.tsx b/src/components/WatchFolder/mappingEntry.tsx index 976e6009bbf9f8c0d3fcdb6d012a9df843b24b2b..510dbdea8e97ce84fe0342eaec0d3a1100dacf4f 100644 --- a/src/components/WatchFolder/mappingEntry.tsx +++ b/src/components/WatchFolder/mappingEntry.tsx @@ -9,9 +9,9 @@ import { } from './styledComponents'; import React, { useEffect, useState } from 'react'; import { CircularProgress, IconButton, Menu, MenuItem } from '@mui/material'; -import watchService from 'services/watchService'; +import watchService from 'services/watchFolderService'; import { SpaceBetweenFlex } from 'components/Container'; -import { WatchMapping } from 'types/watch'; +import { WatchMapping } from 'types/watchFolder'; import { AppContext } from 'pages/_app'; import FolderOpenIcon from '@mui/icons-material/FolderOpen'; import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; diff --git a/src/components/pages/gallery/Upload.tsx b/src/components/pages/gallery/Upload.tsx index ca1b7661cdf2795b1339d57f29fb025daec1076d..77b6d342060774df7e03fa0f0958319d3cf0859a 100644 --- a/src/components/pages/gallery/Upload.tsx +++ b/src/components/pages/gallery/Upload.tsx @@ -24,7 +24,7 @@ import UploadTypeSelector from '../../UploadTypeSelector'; import Router from 'next/router'; import { isCanvasBlocked } from 'utils/upload/isCanvasBlocked'; import { downloadApp } from 'utils/common'; -import watchService from 'services/watchService'; +import watchService from 'services/watchFolderService'; import DiscFullIcon from '@mui/icons-material/DiscFull'; import { NotificationAttributes } from 'types/Notification'; import { diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index dd884eaf5466f2223977c34084830679289ccb18..121faf885d0cbb338ac28c5bdc4b46c87d9151fd 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -38,7 +38,7 @@ import uiService from './uiService'; import { logUploadInfo } from 'utils/upload'; import isElectron from 'is-electron'; import ImportService from 'services/importService'; -import watchService from 'services/watchService'; +import watchService from 'services/watchFolderService'; import { ProgressUpdater } from 'types/upload/ui'; const MAX_CONCURRENT_UPLOADS = 4; diff --git a/src/services/watchService.ts b/src/services/watchFolderService.ts similarity index 99% rename from src/services/watchService.ts rename to src/services/watchFolderService.ts index 7b4d9ed366dca7028480121d701d7f473e5a70ae..d4119347e613cf6e3b5c71415d49e6bf5bdbe9be 100644 --- a/src/services/watchService.ts +++ b/src/services/watchFolderService.ts @@ -6,7 +6,7 @@ import { removeFromCollection, syncCollections } from './collectionService'; import { syncFiles } from './fileService'; import debounce from 'debounce-promise'; import { logError } from 'utils/sentry'; -import { EventQueueItem, WatchMapping } from 'types/watch'; +import { EventQueueItem, WatchMapping } from 'types/watchFolder'; import { ElectronAPIsInterface } from 'types/electron'; export class WatchService { diff --git a/src/types/electron/index.ts b/src/types/electron/index.ts index c5705b5b59ee177d0380d31e2976ea2278a09dc8..448439a1c173182991f4cf67d9ddb0242adf1196 100644 --- a/src/types/electron/index.ts +++ b/src/types/electron/index.ts @@ -1,6 +1,6 @@ -import { WatchService } from 'services/watchService'; +import { WatchService } from 'services/watchFolderService'; import { ElectronFile } from 'types/upload'; -import { WatchMapping } from 'types/watch'; +import { WatchMapping } from 'types/watchFolder'; export interface ElectronAPIsInterface { exists: (path: string) => boolean; diff --git a/src/types/watch/index.ts b/src/types/watchFolder/index.ts similarity index 100% rename from src/types/watch/index.ts rename to src/types/watchFolder/index.ts From 9120ebb7d3154e3286c92a4a5d16c7e66d4200f0 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Wed, 15 Jun 2022 16:20:04 +0530 Subject: [PATCH 038/295] fix clubbing same events --- src/services/watchFolderService.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/services/watchFolderService.ts b/src/services/watchFolderService.ts index d4119347e613cf6e3b5c71415d49e6bf5bdbe9be..5ec0ad240a85da1a18f6d6cdd5ecc35beb1a9005 100644 --- a/src/services/watchFolderService.ts +++ b/src/services/watchFolderService.ts @@ -438,7 +438,11 @@ export class WatchService { event.collectionName === this.eventQueue[0].collectionName && event.type === this.eventQueue[0].type ) { - event.paths = [...event.paths, ...this.eventQueue[0].paths]; + if (event.type === 'trash') { + event.paths = [...event.paths, ...this.eventQueue[0].paths]; + } else { + event.files = [...event.files, ...this.eventQueue[0].files]; + } this.eventQueue.shift(); } return event; From 5d9d92d386365b73014f1501a5f866659fac460c Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Fri, 17 Jun 2022 00:21:08 +0530 Subject: [PATCH 039/295] added overlay for add folder mapping drag and drop screen --- src/components/FullScreenDropZone.tsx | 34 +++++++++++++++++++++-- src/components/Sidebar/UtilitySection.tsx | 14 ++++++---- src/components/WatchFolder/index.tsx | 32 ++++----------------- src/pages/_app.tsx | 19 ++++++++++--- src/pages/gallery/index.tsx | 6 +++- src/utils/strings/englishConstants.tsx | 1 + 6 files changed, 66 insertions(+), 40 deletions(-) diff --git a/src/components/FullScreenDropZone.tsx b/src/components/FullScreenDropZone.tsx index d51ad0fcf080f12f5d8dd882f3315a71795f98f1..3917854103fa3f2bbc04180bca2e4440ffd59b4f 100644 --- a/src/components/FullScreenDropZone.tsx +++ b/src/components/FullScreenDropZone.tsx @@ -1,7 +1,8 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, useContext } from 'react'; import { styled } from '@mui/material'; import constants from 'utils/strings/constants'; import CloseIcon from '@mui/icons-material/Close'; +import { AppContext } from 'pages/_app'; const CloseButtonWrapper = styled('div')` position: absolute; @@ -42,6 +43,8 @@ type Props = React.PropsWithChildren<{ }>; export default function FullScreenDropZone(props: Props) { + const appContext = useContext(AppContext); + const [isDragActive, setIsDragActive] = useState(false); const onDragEnter = () => setIsDragActive(true); const onDragLeave = () => setIsDragActive(false); @@ -53,18 +56,43 @@ export default function FullScreenDropZone(props: Props) { } }); }, []); + + useEffect(() => { + const handleWatchFolderDrop = (e: DragEvent) => { + if (!appContext.watchModalView) { + return; + } + + e.preventDefault(); + e.stopPropagation(); + const files = e.dataTransfer.files; + if (files.length > 0) { + appContext.setWatchModalFiles(files); + } + }; + + addEventListener('drop', handleWatchFolderDrop); + return () => { + removeEventListener('drop', handleWatchFolderDrop); + }; + }, [appContext.watchModalView]); + return ( - + {!appContext.watchModalView ? ( + + ) : null} {isDragActive && ( - {constants.UPLOAD_DROPZONE_MESSAGE} + {appContext.watchModalView + ? constants.WATCH_FOLDER_DROPZONE_MESSAGE + : constants.UPLOAD_DROPZONE_MESSAGE} )} {props.children} diff --git a/src/components/Sidebar/UtilitySection.tsx b/src/components/Sidebar/UtilitySection.tsx index 30487da6b445c4a072b697b1d666d8a25aa04204..d1eadb44e29558c54d236ce9720317c0064ab2de 100644 --- a/src/components/Sidebar/UtilitySection.tsx +++ b/src/components/Sidebar/UtilitySection.tsx @@ -13,11 +13,15 @@ import WatchFolderModal from 'components/WatchFolder'; export default function UtilitySection({ closeSidebar }) { const router = useRouter(); - const { setDialogMessage, startLoading } = useContext(AppContext); + const { + setDialogMessage, + startLoading, + watchModalView, + setWatchModalView, + } = useContext(AppContext); const [recoverModalView, setRecoveryModalView] = useState(false); const [twoFactorModalView, setTwoFactorModalView] = useState(false); - const [watchFolderModalView, setWatchFolderModalView] = useState(false); // const [fixLargeThumbsView, setFixLargeThumbsView] = useState(false); const openRecoveryKeyModal = () => setRecoveryModalView(true); @@ -28,7 +32,7 @@ export default function UtilitySection({ closeSidebar }) { const openWatchModalView = () => { if (isElectron()) { - setWatchFolderModalView(true); + setWatchModalView(true); } else { setDialogMessage({ title: constants.DOWNLOAD_APP, @@ -67,7 +71,7 @@ export default function UtilitySection({ closeSidebar }) { close: { variant: 'danger' }, }); - const closeWatchFolderModal = () => setWatchFolderModalView(false); + const closeWatchFolderModal = () => setWatchModalView(false); return ( <> @@ -105,7 +109,7 @@ export default function UtilitySection({ closeSidebar }) { setLoading={startLoading} /> diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index fda40136b736c409554a527d871ef9645f47fbc7..6a1cf9c6d185e16c2f57ea26424622f0ffc9b15d 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -13,7 +13,7 @@ import watchService from 'services/watchFolderService'; import Close from '@mui/icons-material/Close'; import { CenteredFlex, SpaceBetweenFlex } from 'components/Container'; import { WatchMapping } from 'types/watchFolder'; -import { GalleryContext } from 'pages/gallery'; +import { AppContext } from 'pages/_app'; import constants from 'utils/strings/constants'; import { CheckmarkIcon } from './checkmarkIcon'; import { MappingEntry } from './mappingEntry'; @@ -25,39 +25,17 @@ interface NewType { export default function WatchFolderModal({ open, onClose }: NewType) { const [mappings, setMappings] = useState([]); - const { setDropZoneActive } = useContext(GalleryContext); + const appContext = useContext(AppContext); useEffect(() => { setMappings(watchService.getWatchMappings()); }, []); useEffect(() => { - if (open) { - setDropZoneActive(false); - - const handleDrag = (e: DragEvent) => { - e.preventDefault(); - e.stopPropagation(); - }; - const handleDrop = (e: DragEvent) => { - e.preventDefault(); - e.stopPropagation(); - - const files = e.dataTransfer.files; - if (files.length > 0) { - handleFolderDrop(files); - } - }; - addEventListener('dragover', handleDrag); - addEventListener('drop', handleDrop); - - return () => { - setDropZoneActive(true); - removeEventListener('dragover', handleDrag); - removeEventListener('drop', handleDrop); - }; + if (appContext.watchModalFiles.length > 0) { + handleFolderDrop(appContext.watchModalFiles); } - }, [open]); + }, [appContext.watchModalFiles]); const handleFolderDrop = async (folders: FileList) => { for (let i = 0; i < folders.length; i++) { diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 87afed52be81f59fb81615170a89d2e278253cfd..aef1a787bb9b310fa9b4377ad77041fd818f5f13 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -20,8 +20,8 @@ import { styled, ThemeProvider } from '@mui/material/styles'; import darkThemeOptions from 'themes/darkThemeOptions'; import { CssBaseline } from '@mui/material'; // eslint-disable-next-line @typescript-eslint/no-unused-vars -import * as types from 'styled-components/cssprop'; // need to css prop on styled component -import { SetDialogBoxAttributes, DialogBoxAttributes } from 'types/dialogBox'; +// import * as types from 'styled-components/cssprop'; // need to css prop on styled component +import { DialogBoxAttributes, SetDialogBoxAttributes } from 'types/dialogBox'; import { getFamilyPortalRedirectURL, getRoadmapRedirectURL, @@ -54,6 +54,10 @@ type AppContextType = { setDialogMessage: SetDialogBoxAttributes; watchServiceIsRunning: boolean; setWatchServiceIsRunning: (isRunning: boolean) => void; + watchModalView: boolean; + setWatchModalView: (isOpen: boolean) => void; + watchModalFiles: FileList; + setWatchModalFiles: (files: FileList) => void; }; export enum FLASH_MESSAGE_TYPE { @@ -89,6 +93,10 @@ export default function App({ Component, err }) { const [dialogMessage, setDialogMessage] = useState(); const [messageDialogView, setMessageDialogView] = useState(false); const [watchServiceIsRunning, setWatchServiceIsRunning] = useState(false); + const [watchModalView, setWatchModalView] = useState(false); + const [watchModalFiles, setWatchModalFiles] = useState( + new FileList() + ); useEffect(() => { if ( @@ -148,8 +156,7 @@ export default function App({ Component, err }) { typeof redirectMap.get(redirect) === 'function' ) { const redirectAction = redirectMap.get(redirect); - const url = await redirectAction(); - window.location.href = url; + window.location.href = await redirectAction(); } else { logError(CustomError.BAD_REQUEST, 'invalid redirection', { redirect, @@ -280,6 +287,10 @@ export default function App({ Component, err }) { setDialogMessage, watchServiceIsRunning, setWatchServiceIsRunning, + watchModalView, + setWatchModalView, + watchModalFiles, + setWatchModalFiles, }}> {loading ? ( diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index e817bbf968ec6d5357f18438864416fbcfaaab24..a1292ca246f71a11260028512dc8d0339f6e4dc2 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -279,7 +279,11 @@ export default function Gallery() { [notificationAttributes] ); - useEffect(() => setDroppedFiles(acceptedFiles), [acceptedFiles]); + useEffect(() => { + if (!appContext.watchModalView) { + setDroppedFiles(acceptedFiles); + } + }, [acceptedFiles]); useEffect(() => { if (typeof activeCollection === 'undefined') { diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx index 9203d638b7e00ba81e52983c019f38a924ee9254..3db1ca7788814d3e90b1ad1e0e3fabd4d137ee4a 100644 --- a/src/utils/strings/englishConstants.tsx +++ b/src/utils/strings/englishConstants.tsx @@ -144,6 +144,7 @@ const englishConstants = { UPLOAD_FIRST_PHOTO_DESCRIPTION: 'preserve your first memory with ente', UPLOAD_FIRST_PHOTO: 'Preserve', UPLOAD_DROPZONE_MESSAGE: 'Drop to backup your files', + 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 `, DELETE_FILE: 'Delete files', From 17dd41152e21df8e0054ebf0fb58622a20180088 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Fri, 17 Jun 2022 11:14:12 +0530 Subject: [PATCH 040/295] fix build and bug --- src/components/WatchFolder/index.tsx | 5 ++++- src/pages/_app.tsx | 4 +--- src/services/watchFolderService.ts | 9 +++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index 6a1cf9c6d185e16c2f57ea26424622f0ffc9b15d..0e9233b3dc7d74f352e4bc8b1f7842c8da470401 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -32,7 +32,10 @@ export default function WatchFolderModal({ open, onClose }: NewType) { }, []); useEffect(() => { - if (appContext.watchModalFiles.length > 0) { + if ( + appContext.watchModalFiles && + appContext.watchModalFiles.length > 0 + ) { handleFolderDrop(appContext.watchModalFiles); } }, [appContext.watchModalFiles]); diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index aef1a787bb9b310fa9b4377ad77041fd818f5f13..9d1178e6068ca14c9238ae362dfcb060bdefd721 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -94,9 +94,7 @@ export default function App({ Component, err }) { const [messageDialogView, setMessageDialogView] = useState(false); const [watchServiceIsRunning, setWatchServiceIsRunning] = useState(false); const [watchModalView, setWatchModalView] = useState(false); - const [watchModalFiles, setWatchModalFiles] = useState( - new FileList() - ); + const [watchModalFiles, setWatchModalFiles] = useState(null); useEffect(() => { if ( diff --git a/src/services/watchFolderService.ts b/src/services/watchFolderService.ts index 5ec0ad240a85da1a18f6d6cdd5ecc35beb1a9005..16816cb7da1b533a682dcb4c5ef03b8c20eeb319 100644 --- a/src/services/watchFolderService.ts +++ b/src/services/watchFolderService.ts @@ -261,10 +261,11 @@ export class WatchService { mapping.collectionName === this.currentEvent.collectionName ); - mapping.files = [...mapping.files, ...uploadedFiles]; - - this.ElectronAPIs.setWatchMappings(mappings); - this.syncWithRemote(); + if (mapping) { + mapping.files = [...mapping.files, ...uploadedFiles]; + this.ElectronAPIs.setWatchMappings(mappings); + this.syncWithRemote(); + } } this.setIsEventRunning(false); From 6cef3352645b2059b8db44c920fbed68095d44ad Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Fri, 17 Jun 2022 12:05:34 +0530 Subject: [PATCH 041/295] clear electron store on logout --- src/services/userService.ts | 11 +++++++++++ src/types/electron/index.ts | 1 + 2 files changed, 12 insertions(+) diff --git a/src/services/userService.ts b/src/services/userService.ts index 496ec9c7ef0a8365f5807c659852775e34d4797f..30508997c01c807d349da53f7b8d4d34ef5aca83 100644 --- a/src/services/userService.ts +++ b/src/services/userService.ts @@ -19,6 +19,9 @@ import { } from 'types/user'; import { getFamilyData, isPartOfFamily } from 'utils/billing'; import { ServerErrorCodes } from 'utils/error'; +import isElectron from 'is-electron'; +import { runningInBrowser } from '../utils/common'; +import { ElectronAPIsInterface } from '../types/electron'; const ENDPOINT = getEndpoint(); @@ -121,6 +124,14 @@ export const logoutUser = async () => { // ignore } await clearFiles(); + + if (isElectron()) { + const ElectronAPIs = (runningInBrowser() && + window['ElectronAPIs']) as ElectronAPIsInterface; + if (ElectronAPIs && ElectronAPIs.clearElectronStore) { + ElectronAPIs.clearElectronStore(); + } + } router.push(PAGES.ROOT); } catch (e) { logError(e, 'logoutUser failed'); diff --git a/src/types/electron/index.ts b/src/types/electron/index.ts index 448439a1c173182991f4cf67d9ddb0242adf1196..9851b43340144ab2f124a6a0ba22eaa49fa4c2fa 100644 --- a/src/types/electron/index.ts +++ b/src/types/electron/index.ts @@ -62,4 +62,5 @@ export interface ElectronAPIsInterface { ) => Promise ) => void; doesFolderExists: (dirPath: string) => Promise; + clearElectronStore: () => void; } From 9f0cadacaa3c11292773e74dff3ecd1425cd464a Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 15 Jun 2022 19:28:49 +0530 Subject: [PATCH 042/295] udpate type --- src/components/WatchFolder/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index 0e9233b3dc7d74f352e4bc8b1f7842c8da470401..62fa012311c8c16bb5634add405da1ae6e05f7a4 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -18,12 +18,12 @@ import constants from 'utils/strings/constants'; import { CheckmarkIcon } from './checkmarkIcon'; import { MappingEntry } from './mappingEntry'; -interface NewType { +interface Iprops { open: boolean; onClose: () => void; } -export default function WatchFolderModal({ open, onClose }: NewType) { +export default function WatchFolderModal({ open, onClose }: Iprops) { const [mappings, setMappings] = useState([]); const appContext = useContext(AppContext); From 03e29c6227621fabc0b77a8a20d00ec1dbe3a040 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sun, 19 Jun 2022 13:20:19 +0530 Subject: [PATCH 043/295] refactor components --- src/components/WatchFolder/checkmarkIcon.tsx | 13 +- src/components/WatchFolder/index.tsx | 111 +++++--------- src/components/WatchFolder/mappingEntry.tsx | 136 ------------------ .../WatchFolder/mappingEntry/entryHeading.tsx | 24 ++++ .../WatchFolder/mappingEntry/index.tsx | 55 +++++++ .../mappingEntry/syncProgressIcon.tsx | 13 ++ .../WatchFolder/mappingEntryOptions.tsx | 55 +++++++ src/components/WatchFolder/mappingList.tsx | 19 +++ .../WatchFolder/noMappingsContent.tsx | 24 ++++ .../WatchFolder/styledComponents.tsx | 85 +++-------- 10 files changed, 246 insertions(+), 289 deletions(-) delete mode 100644 src/components/WatchFolder/mappingEntry.tsx create mode 100644 src/components/WatchFolder/mappingEntry/entryHeading.tsx create mode 100644 src/components/WatchFolder/mappingEntry/index.tsx create mode 100644 src/components/WatchFolder/mappingEntry/syncProgressIcon.tsx create mode 100644 src/components/WatchFolder/mappingEntryOptions.tsx create mode 100644 src/components/WatchFolder/mappingList.tsx create mode 100644 src/components/WatchFolder/noMappingsContent.tsx diff --git a/src/components/WatchFolder/checkmarkIcon.tsx b/src/components/WatchFolder/checkmarkIcon.tsx index 28bf54fdb023ee48de0b014b10c274a6be938469..75805d9c94420be1df6fa1eacb53a47b9d1ed48a 100644 --- a/src/components/WatchFolder/checkmarkIcon.tsx +++ b/src/components/WatchFolder/checkmarkIcon.tsx @@ -1,16 +1,13 @@ import React from 'react'; -import { Icon } from '@mui/material'; import CheckIcon from '@mui/icons-material/Check'; export function CheckmarkIcon() { return ( - theme.palette.grey.A200, - }}> - - + marginRight: '8px', + color: (theme) => theme.palette.secondary.main, + }} + /> ); } diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index 62fa012311c8c16bb5634add405da1ae6e05f7a4..44e3b68cb9a036743db0d892065373046ed6837f 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -1,22 +1,13 @@ -import { - BottomMarginSpacer, - FixedHeightContainer, - FullHeightVerticallyCentered, - FullWidthButtonWithTopMargin, - ModalHeading, - NoFoldersTitleText, - PaddedContainer, -} from './styledComponents'; +import { MappingList } from './mappingList'; +import { NoMappingsContent } from './noMappingsContent'; import React, { useContext, useEffect, useState } from 'react'; -import { Dialog, IconButton } from '@mui/material'; +import { Button, DialogActions, DialogContent } from '@mui/material'; import watchService from 'services/watchFolderService'; -import Close from '@mui/icons-material/Close'; -import { CenteredFlex, SpaceBetweenFlex } from 'components/Container'; import { WatchMapping } from 'types/watchFolder'; import { AppContext } from 'pages/_app'; import constants from 'utils/strings/constants'; -import { CheckmarkIcon } from './checkmarkIcon'; -import { MappingEntry } from './mappingEntry'; +import DialogBoxBase from 'components/DialogBox/base'; +import DialogTitleWithCloseButton from 'components/DialogBox/titleWithCloseButton'; interface Iprops { open: boolean; @@ -75,69 +66,35 @@ export default function WatchFolderModal({ open, onClose }: Iprops) { }; return ( - - - - - {constants.WATCHED_FOLDERS} - - - - + + + {constants.WATCHED_FOLDERS} + + + {mappings.length !== 0 ? ( + + ) : ( + + )} + - {mappings.length === 0 ? ( - - - {constants.NO_FOLDERS_ADDED} - - {constants.FOLDERS_AUTOMATICALLY_MONITORED} - - - {' '} - {constants.UPLOAD_NEW_FILES_TO_ENTE} - - - {' '} - {constants.REMOVE_DELETED_FILES_FROM_ENTE} - - - ) : ( - - {mappings.map((mapping: WatchMapping) => { - return ( - - ); - })} - - )} - - - - + - - {constants.ADD_FOLDER} - - - - - + + + + ); } diff --git a/src/components/WatchFolder/mappingEntry.tsx b/src/components/WatchFolder/mappingEntry.tsx deleted file mode 100644 index 510dbdea8e97ce84fe0342eaec0d3a1100dacf4f..0000000000000000000000000000000000000000 --- a/src/components/WatchFolder/mappingEntry.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import { - DialogBoxButton, - DialogBoxHeading, - DialogBoxText, - HorizontalFlex, - MappingEntryFolder, - MappingEntryTitle, - VerticalFlex, -} from './styledComponents'; -import React, { useEffect, useState } from 'react'; -import { CircularProgress, IconButton, Menu, MenuItem } from '@mui/material'; -import watchService from 'services/watchFolderService'; -import { SpaceBetweenFlex } from 'components/Container'; -import { WatchMapping } from 'types/watchFolder'; -import { AppContext } from 'pages/_app'; -import FolderOpenIcon from '@mui/icons-material/FolderOpen'; -import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; -import DoNotDisturbOutlinedIcon from '@mui/icons-material/DoNotDisturbOutlined'; -import DialogBox from '../DialogBox'; -import constants from 'utils/strings/constants'; - -export function MappingEntry({ - mapping, - handleRemoveMapping, -}: { - mapping: WatchMapping; - handleRemoveMapping: (mapping: WatchMapping) => void; -}) { - const appContext = React.useContext(AppContext); - - useEffect(() => { - console.log(appContext.watchServiceIsRunning); - }, [appContext.watchServiceIsRunning]); - - const [anchorEl, setAnchorEl] = useState(null); - const [dialogBoxOpen, setDialogBoxOpen] = useState(false); - const open = Boolean(anchorEl); - const handleClick = (event: React.MouseEvent) => { - setAnchorEl(event.currentTarget); - }; - const handleClose = () => { - setAnchorEl(null); - }; - - return ( - <> - - - - - - {mapping.collectionName} - {appContext.watchServiceIsRunning && - watchService.currentEvent?.collectionName === - mapping.collectionName && ( - - )} - - theme.palette.grey[500], - }}> - {mapping.folderPath} - - - - - - - - - setDialogBoxOpen(true)} - sx={{ - fontWeight: 600, - color: (theme) => theme.palette.danger.main, - }}> - - - {' '} - {constants.STOP_WATCHING} - - - setDialogBoxOpen(false)} - attributes={{}}> - - {constants.STOP_WATCHING_FOLDER} - - - {constants.STOP_WATCHING_DIALOG_MESSAGE} - - - setDialogBoxOpen(false)}> - {constants.CANCEL} - - handleRemoveMapping(mapping)}> - {constants.YES_STOP} - - - - - ); -} diff --git a/src/components/WatchFolder/mappingEntry/entryHeading.tsx b/src/components/WatchFolder/mappingEntry/entryHeading.tsx new file mode 100644 index 0000000000000000000000000000000000000000..fb6347021fc3bbe734d0d396b7964a073b31d501 --- /dev/null +++ b/src/components/WatchFolder/mappingEntry/entryHeading.tsx @@ -0,0 +1,24 @@ +import React, { useContext } from 'react'; +import { Typography } from '@mui/material'; +import watchService from 'services/watchFolderService'; +import { AppContext } from 'pages/_app'; +import { SyncProgressIcon } from './syncProgressIcon'; + +export function EntryHeading({ mapping }) { + const appContext = useContext(AppContext); + return ( + + <> + {mapping.collectionName} + {appContext.watchServiceIsRunning && + watchService.currentEvent?.collectionName === + mapping.collectionName && } + + + ); +} diff --git a/src/components/WatchFolder/mappingEntry/index.tsx b/src/components/WatchFolder/mappingEntry/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f20badd38597dbe0d73e3aa4898b6628a7553a15 --- /dev/null +++ b/src/components/WatchFolder/mappingEntry/index.tsx @@ -0,0 +1,55 @@ +import { EntryContainer, HorizontalFlex } from '../styledComponents'; +import React, { useEffect } from 'react'; +import { Typography } from '@mui/material'; +import { SpaceBetweenFlex } from 'components/Container'; +import { WatchMapping } from 'types/watchFolder'; +import { AppContext } from 'pages/_app'; +import FolderOpenIcon from '@mui/icons-material/FolderOpen'; +import constants from 'utils/strings/constants'; +import MappingEntryOptions from '../mappingEntryOptions'; +import { EntryHeading } from './entryHeading'; + +export function MappingEntry({ + mapping, + handleRemoveMapping, +}: { + mapping: WatchMapping; + handleRemoveMapping: (mapping: WatchMapping) => void; +}) { + const appContext = React.useContext(AppContext); + + useEffect(() => { + console.log(appContext.watchServiceIsRunning); + }, [appContext.watchServiceIsRunning]); + + const confirmStopWatching = () => { + appContext.setDialogMessage({ + title: constants.STOP_WATCHING_FOLDER, + content: constants.STOP_WATCHING_DIALOG_MESSAGE, + close: { + text: constants.CANCEL, + variant: 'primary', + }, + proceed: { + action: () => handleRemoveMapping(mapping), + text: constants.YES_STOP, + variant: 'danger', + }, + }); + }; + + return ( + + + + + + + {mapping.folderPath} + + + + + + ); +} diff --git a/src/components/WatchFolder/mappingEntry/syncProgressIcon.tsx b/src/components/WatchFolder/mappingEntry/syncProgressIcon.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d221a7fb7b34c98eacda665850a5b42eec63d961 --- /dev/null +++ b/src/components/WatchFolder/mappingEntry/syncProgressIcon.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { CircularProgress } from '@mui/material'; + +export function SyncProgressIcon() { + return ( + + ); +} diff --git a/src/components/WatchFolder/mappingEntryOptions.tsx b/src/components/WatchFolder/mappingEntryOptions.tsx new file mode 100644 index 0000000000000000000000000000000000000000..10e9a7001aa5015bcb81b538f4d21be00001ec19 --- /dev/null +++ b/src/components/WatchFolder/mappingEntryOptions.tsx @@ -0,0 +1,55 @@ +import { IconButton, Menu, MenuItem } from '@mui/material'; +import React, { useState } from 'react'; +import constants from 'utils/strings/constants'; +import DoNotDisturbOutlinedIcon from '@mui/icons-material/DoNotDisturbOutlined'; +import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; + +export default function MappingEntryOptions({ confirmStopWatching }) { + const [anchorEl, setAnchorEl] = useState(null); + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + const handleClose = () => { + setAnchorEl(null); + }; + + const open = Boolean(anchorEl); + return ( + <> + + + + + theme.palette.danger.main, + }}> + + + + {constants.STOP_WATCHING} + + + + ); +} diff --git a/src/components/WatchFolder/mappingList.tsx b/src/components/WatchFolder/mappingList.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c495bed301391be4d68a4c2a05e113207ca7f61b --- /dev/null +++ b/src/components/WatchFolder/mappingList.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { MappingEntry } from './mappingEntry'; +import { MappingsContainer } from './styledComponents'; +export function MappingList({ mappings, handleRemoveWatchMapping }) { + return ( + + {mappings.map((mapping) => { + console.log(mapping); + return ( + + ); + })} + + ); +} diff --git a/src/components/WatchFolder/noMappingsContent.tsx b/src/components/WatchFolder/noMappingsContent.tsx new file mode 100644 index 0000000000000000000000000000000000000000..54eccf06bebb9aee55b77b0b40c99145cada305e --- /dev/null +++ b/src/components/WatchFolder/noMappingsContent.tsx @@ -0,0 +1,24 @@ +import { Typography } from '@mui/material'; +import { FlexWrapper } from 'components/Container'; +import React from 'react'; +import constants from 'utils/strings/constants'; +import { CheckmarkIcon } from './checkmarkIcon'; +import { NoMappingsContainer } from './styledComponents'; +export function NoMappingsContent() { + return ( + + + {constants.NO_FOLDERS_ADDED} + + + {constants.FOLDERS_AUTOMATICALLY_MONITORED} + + + {constants.UPLOAD_NEW_FILES_TO_ENTE} + + + {constants.REMOVE_DELETED_FILES_FROM_ENTE} + + + ); +} diff --git a/src/components/WatchFolder/styledComponents.tsx b/src/components/WatchFolder/styledComponents.tsx index 20ca60e1f5abbf3efc2dcd1e4dceffa67aed6567..20e69e4571951f6535dea413b46bd598cd21fd17 100644 --- a/src/components/WatchFolder/styledComponents.tsx +++ b/src/components/WatchFolder/styledComponents.tsx @@ -1,81 +1,30 @@ -import { Box, Button } from '@mui/material'; +import { Box } from '@mui/material'; import { styled } from '@mui/material/styles'; +import VerticallyCentered from 'components/Container'; -export const ModalHeading = styled('h3')({ - fontSize: '28px', - marginBottom: '24px', - fontWeight: 600, -}); -export const FullWidthButtonWithTopMargin = styled(Button)({ - marginTop: '16px', - width: '100%', - borderRadius: '4px', -}); -export const PaddedContainer = styled(Box)({ - padding: '24px', -}); -export const FixedHeightContainer = styled(Box)({ - height: '450px', - display: 'flex', - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'space-between', -}); -export const FullHeightVerticallyCentered = styled(Box)({ - display: 'flex', - flexDirection: 'column', - height: '100%', - overflowY: 'auto', - margin: 0, - padding: 0, - listStyle: 'none', +export const MappingsContainer = styled(Box)(({ theme }) => ({ + height: '278px', + overflow: 'auto', '&::-webkit-scrollbar': { - width: '6px', + width: '4px', }, '&::-webkit-scrollbar-thumb': { - backgroundColor: 'slategrey', + backgroundColor: theme.palette.secondary.main, }, +})); + +export const NoMappingsContainer = styled(VerticallyCentered)({ + height: '278px', + textAlign: 'left', + alignItems: 'flex-start', }); -export const NoFoldersTitleText = styled('h4')({ - fontSize: '24px', - marginBottom: '16px', - fontWeight: 600, -}); -export const BottomMarginSpacer = styled(Box)({ - marginBottom: '10px', -}); + export const HorizontalFlex = styled(Box)({ display: 'flex', - flexDirection: 'row', - justifyContent: 'space-between', }); -export const VerticalFlex = styled(Box)({ - display: 'flex', - flexDirection: 'column', -}); -export const MappingEntryTitle = styled(Box)({ - fontSize: '16px', - fontWeight: 500, - marginLeft: '12px', - marginRight: '6px', -}); -export const MappingEntryFolder = styled(Box)({ - fontSize: '14px', - fontWeight: 500, - marginTop: '2px', + +export const EntryContainer = styled(Box)({ marginLeft: '12px', marginRight: '6px', - marginBottom: '6px', - lineHeight: '18px', -}); -export const DialogBoxHeading = styled('h4')({ - fontSize: '24px', - marginBottom: '16px', - fontWeight: 600, -}); -export const DialogBoxText = styled('p')({ - fontWeight: 500, -}); -export const DialogBoxButton = styled(Button)({ - width: '140px', + marginBottom: '12px', }); From 8f2b1b0be69fdca0f09f4e97e929bb5d503a2514 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sun, 19 Jun 2022 13:27:42 +0530 Subject: [PATCH 044/295] revert testing change --- src/components/WatchFolder/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index 44e3b68cb9a036743db0d892065373046ed6837f..5915657889d713e3dd38538a4a3b3b9e43ecc0ed 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -71,7 +71,7 @@ export default function WatchFolderModal({ open, onClose }: Iprops) { {constants.WATCHED_FOLDERS} - {mappings.length !== 0 ? ( + {mappings.length === 0 ? ( ) : ( Date: Sun, 19 Jun 2022 16:18:47 +0530 Subject: [PATCH 045/295] fix typo --- src/components/UploadProgress/index.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/UploadProgress/index.tsx b/src/components/UploadProgress/index.tsx index 293b6fb4b9aa8b4de9ef3ccac18c80ea6a04eafc..03baed0f9849191215b4a2097e35ab3d0e3b45d2 100644 --- a/src/components/UploadProgress/index.tsx +++ b/src/components/UploadProgress/index.tsx @@ -45,7 +45,10 @@ export default function UploadProgress({ const [expanded, setExpanded] = useState(true); useEffect(() => { - if (appContext.watchServiceIsRunning && watchService.isUploadRunning) { + if ( + appContext.watchServiceIsRunning && + watchService.isUploadRunning() + ) { setExpanded(false); } }, [appContext.watchServiceIsRunning]); From 6b9ed0c6228bd81d85b67729c7663b7eb1463273 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sun, 19 Jun 2022 16:29:41 +0530 Subject: [PATCH 046/295] rename watchModal to watchFolder --- src/components/FullScreenDropZone.tsx | 10 +++---- src/components/Sidebar/UtilitySection.tsx | 13 ++++---- src/components/UploadProgress/index.tsx | 7 ++--- src/components/WatchFolder/index.tsx | 10 +++---- .../WatchFolder/mappingEntry/entryHeading.tsx | 2 +- .../WatchFolder/mappingEntry/index.tsx | 4 +-- src/components/pages/gallery/Upload.tsx | 2 +- src/pages/_app.tsx | 30 +++++++++---------- src/pages/gallery/index.tsx | 2 +- 9 files changed, 37 insertions(+), 43 deletions(-) diff --git a/src/components/FullScreenDropZone.tsx b/src/components/FullScreenDropZone.tsx index 3917854103fa3f2bbc04180bca2e4440ffd59b4f..46ff6de8cd980833e9082144e0cd87aa7af5b97d 100644 --- a/src/components/FullScreenDropZone.tsx +++ b/src/components/FullScreenDropZone.tsx @@ -59,7 +59,7 @@ export default function FullScreenDropZone(props: Props) { useEffect(() => { const handleWatchFolderDrop = (e: DragEvent) => { - if (!appContext.watchModalView) { + if (!appContext.watchFolderView) { return; } @@ -67,7 +67,7 @@ export default function FullScreenDropZone(props: Props) { e.stopPropagation(); const files = e.dataTransfer.files; if (files.length > 0) { - appContext.setWatchModalFiles(files); + appContext.setWatchFolderFiles(files); } }; @@ -75,14 +75,14 @@ export default function FullScreenDropZone(props: Props) { return () => { removeEventListener('drop', handleWatchFolderDrop); }; - }, [appContext.watchModalView]); + }, [appContext.watchFolderView]); return ( - {!appContext.watchModalView ? ( + {!appContext.watchFolderView ? ( ) : null} {isDragActive && ( @@ -90,7 +90,7 @@ export default function FullScreenDropZone(props: Props) { - {appContext.watchModalView + {appContext.watchFolderView ? constants.WATCH_FOLDER_DROPZONE_MESSAGE : constants.UPLOAD_DROPZONE_MESSAGE} diff --git a/src/components/Sidebar/UtilitySection.tsx b/src/components/Sidebar/UtilitySection.tsx index d1eadb44e29558c54d236ce9720317c0064ab2de..696e260baa5794260835391a63eef0db3d47b006 100644 --- a/src/components/Sidebar/UtilitySection.tsx +++ b/src/components/Sidebar/UtilitySection.tsx @@ -9,15 +9,15 @@ import { useRouter } from 'next/router'; import { AppContext } from 'pages/_app'; import isElectron from 'is-electron'; import { downloadApp } from 'utils/common'; -import WatchFolderModal from 'components/WatchFolder'; +import WatchFolder from 'components/WatchFolder'; export default function UtilitySection({ closeSidebar }) { const router = useRouter(); const { setDialogMessage, startLoading, - watchModalView, - setWatchModalView, + watchFolderView: watchModalView, + setWatchFolderView: setWatchModalView, } = useContext(AppContext); const [recoverModalView, setRecoveryModalView] = useState(false); @@ -71,7 +71,7 @@ export default function UtilitySection({ closeSidebar }) { close: { variant: 'danger' }, }); - const closeWatchFolderModal = () => setWatchModalView(false); + const closeWatchFolder = () => setWatchModalView(false); return ( <> @@ -108,10 +108,7 @@ export default function UtilitySection({ closeSidebar }) { closeSidebar={closeSidebar} setLoading={startLoading} /> - + {/* { - if ( - appContext.watchServiceIsRunning && - watchService.isUploadRunning() - ) { + if (appContext.isFolderSyncRunning && watchService.isUploadRunning()) { setExpanded(false); } - }, [appContext.watchServiceIsRunning]); + }, [appContext.isFolderSyncRunning]); function confirmCancelUpload() { appContext.setDialogMessage({ diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index 5915657889d713e3dd38538a4a3b3b9e43ecc0ed..b4ef294b9cd29ad2ca4299e666771dc234502440 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -14,7 +14,7 @@ interface Iprops { onClose: () => void; } -export default function WatchFolderModal({ open, onClose }: Iprops) { +export default function WatchFolder({ open, onClose }: Iprops) { const [mappings, setMappings] = useState([]); const appContext = useContext(AppContext); @@ -24,12 +24,12 @@ export default function WatchFolderModal({ open, onClose }: Iprops) { useEffect(() => { if ( - appContext.watchModalFiles && - appContext.watchModalFiles.length > 0 + appContext.watchModalFolderFiles && + appContext.watchModalFolderFiles.length > 0 ) { - handleFolderDrop(appContext.watchModalFiles); + handleFolderDrop(appContext.watchModalFolderFiles); } - }, [appContext.watchModalFiles]); + }, [appContext.watchModalFolderFiles]); const handleFolderDrop = async (folders: FileList) => { for (let i = 0; i < folders.length; i++) { diff --git a/src/components/WatchFolder/mappingEntry/entryHeading.tsx b/src/components/WatchFolder/mappingEntry/entryHeading.tsx index fb6347021fc3bbe734d0d396b7964a073b31d501..5fc7a28b8525287cf2cffb9199fdb502f0e8ae61 100644 --- a/src/components/WatchFolder/mappingEntry/entryHeading.tsx +++ b/src/components/WatchFolder/mappingEntry/entryHeading.tsx @@ -15,7 +15,7 @@ export function EntryHeading({ mapping }) { }}> <> {mapping.collectionName} - {appContext.watchServiceIsRunning && + {appContext.isFolderSyncRunning && watchService.currentEvent?.collectionName === mapping.collectionName && } diff --git a/src/components/WatchFolder/mappingEntry/index.tsx b/src/components/WatchFolder/mappingEntry/index.tsx index f20badd38597dbe0d73e3aa4898b6628a7553a15..7451cdebb3a40061e54f75e9f7e6cdf3672fd600 100644 --- a/src/components/WatchFolder/mappingEntry/index.tsx +++ b/src/components/WatchFolder/mappingEntry/index.tsx @@ -19,8 +19,8 @@ export function MappingEntry({ const appContext = React.useContext(AppContext); useEffect(() => { - console.log(appContext.watchServiceIsRunning); - }, [appContext.watchServiceIsRunning]); + console.log(appContext.isFolderSyncRunning); + }, [appContext.isFolderSyncRunning]); const confirmStopWatching = () => { appContext.setDialogMessage({ diff --git a/src/components/pages/gallery/Upload.tsx b/src/components/pages/gallery/Upload.tsx index e511f0dc01e2a4b51110ecd49b23b078a9638b91..96e166a7b5622033e3557cfa1c4397b2108829b5 100644 --- a/src/components/pages/gallery/Upload.tsx +++ b/src/components/pages/gallery/Upload.tsx @@ -132,7 +132,7 @@ export default function Upload(props: Props) { props.setElectronFiles, setCollectionName, props.syncWithRemote, - appContext.setWatchServiceIsRunning + appContext.setIsFolderSyncRunning ); } }, []); diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 9d1178e6068ca14c9238ae362dfcb060bdefd721..f4023ecd325c0e832d2ba87928a51b280e1d02c8 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -52,12 +52,12 @@ type AppContextType = { finishLoading: () => void; closeMessageDialog: () => void; setDialogMessage: SetDialogBoxAttributes; - watchServiceIsRunning: boolean; - setWatchServiceIsRunning: (isRunning: boolean) => void; - watchModalView: boolean; - setWatchModalView: (isOpen: boolean) => void; - watchModalFiles: FileList; - setWatchModalFiles: (files: FileList) => void; + isFolderSyncRunning: boolean; + setIsFolderSyncRunning: (isRunning: boolean) => void; + watchFolderView: boolean; + setWatchFolderView: (isOpen: boolean) => void; + watchModalFolderFiles: FileList; + setWatchFolderFiles: (files: FileList) => void; }; export enum FLASH_MESSAGE_TYPE { @@ -92,9 +92,9 @@ export default function App({ Component, err }) { const loadingBar = useRef(null); const [dialogMessage, setDialogMessage] = useState(); const [messageDialogView, setMessageDialogView] = useState(false); - const [watchServiceIsRunning, setWatchServiceIsRunning] = useState(false); - const [watchModalView, setWatchModalView] = useState(false); - const [watchModalFiles, setWatchModalFiles] = useState(null); + const [isFolderSyncRunning, setIsFolderSyncRunning] = useState(false); + const [watchFolderView, setWatchFolderView] = useState(false); + const [watchFolderFiles, setWatchFolderFiles] = useState(null); useEffect(() => { if ( @@ -283,12 +283,12 @@ export default function App({ Component, err }) { finishLoading, closeMessageDialog, setDialogMessage, - watchServiceIsRunning, - setWatchServiceIsRunning, - watchModalView, - setWatchModalView, - watchModalFiles, - setWatchModalFiles, + isFolderSyncRunning: isFolderSyncRunning, + setIsFolderSyncRunning: setIsFolderSyncRunning, + watchFolderView: watchFolderView, + setWatchFolderView: setWatchFolderView, + watchModalFolderFiles: watchFolderFiles, + setWatchFolderFiles: setWatchFolderFiles, }}> {loading ? ( diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index a1292ca246f71a11260028512dc8d0339f6e4dc2..f2bc7e996a23890823463f676dc54b0a6913787d 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -280,7 +280,7 @@ export default function Gallery() { ); useEffect(() => { - if (!appContext.watchModalView) { + if (!appContext.watchFolderView) { setDroppedFiles(acceptedFiles); } }, [acceptedFiles]); From 0138873881dba21ca2906e20ba6d2235b154a312 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sun, 19 Jun 2022 16:32:14 +0530 Subject: [PATCH 047/295] update EntryHeading styles --- .../WatchFolder/mappingEntry/entryHeading.tsx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/components/WatchFolder/mappingEntry/entryHeading.tsx b/src/components/WatchFolder/mappingEntry/entryHeading.tsx index 5fc7a28b8525287cf2cffb9199fdb502f0e8ae61..e25bc2442cc8042d16b54d60d7f62bc01142992c 100644 --- a/src/components/WatchFolder/mappingEntry/entryHeading.tsx +++ b/src/components/WatchFolder/mappingEntry/entryHeading.tsx @@ -3,22 +3,22 @@ import { Typography } from '@mui/material'; import watchService from 'services/watchFolderService'; import { AppContext } from 'pages/_app'; import { SyncProgressIcon } from './syncProgressIcon'; +import { FlexWrapper } from 'components/Container'; export function EntryHeading({ mapping }) { const appContext = useContext(AppContext); return ( - - <> + + {mapping.collectionName} - {appContext.isFolderSyncRunning && - watchService.currentEvent?.collectionName === - mapping.collectionName && } - - + + {appContext.isFolderSyncRunning && + watchService.currentEvent?.collectionName === + mapping.collectionName && } + ); } From e51e6e8fa1b1d8692233a2bda21b3d01d07eba22 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sun, 19 Jun 2022 16:40:17 +0530 Subject: [PATCH 048/295] add typings --- .../WatchFolder/mappingEntry/entryHeading.tsx | 7 ++++++- src/components/WatchFolder/mappingEntry/index.tsx | 15 +++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/components/WatchFolder/mappingEntry/entryHeading.tsx b/src/components/WatchFolder/mappingEntry/entryHeading.tsx index e25bc2442cc8042d16b54d60d7f62bc01142992c..1c9ce028d7145ae79dc4766dccd830d571602b81 100644 --- a/src/components/WatchFolder/mappingEntry/entryHeading.tsx +++ b/src/components/WatchFolder/mappingEntry/entryHeading.tsx @@ -4,8 +4,13 @@ import watchService from 'services/watchFolderService'; import { AppContext } from 'pages/_app'; import { SyncProgressIcon } from './syncProgressIcon'; import { FlexWrapper } from 'components/Container'; +import { WatchMapping } from 'types/watchFolder'; -export function EntryHeading({ mapping }) { +interface Iprops { + mapping: WatchMapping; +} + +export function EntryHeading({ mapping }: Iprops) { const appContext = useContext(AppContext); return ( diff --git a/src/components/WatchFolder/mappingEntry/index.tsx b/src/components/WatchFolder/mappingEntry/index.tsx index 7451cdebb3a40061e54f75e9f7e6cdf3672fd600..7e5f083144467826dbf0b03695f9a6a6ed0d3947 100644 --- a/src/components/WatchFolder/mappingEntry/index.tsx +++ b/src/components/WatchFolder/mappingEntry/index.tsx @@ -1,5 +1,5 @@ import { EntryContainer, HorizontalFlex } from '../styledComponents'; -import React, { useEffect } from 'react'; +import React from 'react'; import { Typography } from '@mui/material'; import { SpaceBetweenFlex } from 'components/Container'; import { WatchMapping } from 'types/watchFolder'; @@ -9,18 +9,13 @@ import constants from 'utils/strings/constants'; import MappingEntryOptions from '../mappingEntryOptions'; import { EntryHeading } from './entryHeading'; -export function MappingEntry({ - mapping, - handleRemoveMapping, -}: { +interface Iprops { mapping: WatchMapping; handleRemoveMapping: (mapping: WatchMapping) => void; -}) { - const appContext = React.useContext(AppContext); +} - useEffect(() => { - console.log(appContext.isFolderSyncRunning); - }, [appContext.isFolderSyncRunning]); +export function MappingEntry({ mapping, handleRemoveMapping }: Iprops) { + const appContext = React.useContext(AppContext); const confirmStopWatching = () => { appContext.setDialogMessage({ From 323b6af010e96c3c5dbd0595ac83e7cebac5c5fd Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sun, 19 Jun 2022 16:41:52 +0530 Subject: [PATCH 049/295] rename missed watchModal to watchFolder --- src/components/Sidebar/UtilitySection.tsx | 14 +++++++------- src/components/WatchFolder/index.tsx | 8 ++++---- src/pages/_app.tsx | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/components/Sidebar/UtilitySection.tsx b/src/components/Sidebar/UtilitySection.tsx index 696e260baa5794260835391a63eef0db3d47b006..b544d3117a542d1df2389b61deb898783b44b21a 100644 --- a/src/components/Sidebar/UtilitySection.tsx +++ b/src/components/Sidebar/UtilitySection.tsx @@ -16,8 +16,8 @@ export default function UtilitySection({ closeSidebar }) { const { setDialogMessage, startLoading, - watchFolderView: watchModalView, - setWatchFolderView: setWatchModalView, + watchFolderView, + setWatchFolderView, } = useContext(AppContext); const [recoverModalView, setRecoveryModalView] = useState(false); @@ -30,9 +30,9 @@ export default function UtilitySection({ closeSidebar }) { const openTwoFactorModalView = () => setTwoFactorModalView(true); const closeTwoFactorModalView = () => setTwoFactorModalView(false); - const openWatchModalView = () => { + const openWatchFolderView = () => { if (isElectron()) { - setWatchModalView(true); + setWatchFolderView(true); } else { setDialogMessage({ title: constants.DOWNLOAD_APP, @@ -71,7 +71,7 @@ export default function UtilitySection({ closeSidebar }) { close: { variant: 'danger' }, }); - const closeWatchFolder = () => setWatchModalView(false); + const closeWatchFolder = () => setWatchFolderView(false); return ( <> @@ -89,7 +89,7 @@ export default function UtilitySection({ closeSidebar }) { {constants.DEDUPLICATE_FILES} - + {constants.WATCH_FOLDERS} @@ -108,7 +108,7 @@ export default function UtilitySection({ closeSidebar }) { closeSidebar={closeSidebar} setLoading={startLoading} /> - + {/* { if ( - appContext.watchModalFolderFiles && - appContext.watchModalFolderFiles.length > 0 + appContext.watchFolderFiles && + appContext.watchFolderFiles.length > 0 ) { - handleFolderDrop(appContext.watchModalFolderFiles); + handleFolderDrop(appContext.watchFolderFiles); } - }, [appContext.watchModalFolderFiles]); + }, [appContext.watchFolderFiles]); const handleFolderDrop = async (folders: FileList) => { for (let i = 0; i < folders.length; i++) { diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index f4023ecd325c0e832d2ba87928a51b280e1d02c8..ddf2833157a219685d055836edbfc23634ea31c7 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -56,7 +56,7 @@ type AppContextType = { setIsFolderSyncRunning: (isRunning: boolean) => void; watchFolderView: boolean; setWatchFolderView: (isOpen: boolean) => void; - watchModalFolderFiles: FileList; + watchFolderFiles: FileList; setWatchFolderFiles: (files: FileList) => void; }; @@ -287,7 +287,7 @@ export default function App({ Component, err }) { setIsFolderSyncRunning: setIsFolderSyncRunning, watchFolderView: watchFolderView, setWatchFolderView: setWatchFolderView, - watchModalFolderFiles: watchFolderFiles, + watchFolderFiles: watchFolderFiles, setWatchFolderFiles: setWatchFolderFiles, }}> {loading ? ( From 6832ae46ff9f3ab9a00a842380a5c44d2b237bf1 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sun, 19 Jun 2022 16:44:03 +0530 Subject: [PATCH 050/295] add more typing --- src/components/WatchFolder/mappingList.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/WatchFolder/mappingList.tsx b/src/components/WatchFolder/mappingList.tsx index c495bed301391be4d68a4c2a05e113207ca7f61b..1578ed7af90f1b4e9871e15a4b44f695a225f524 100644 --- a/src/components/WatchFolder/mappingList.tsx +++ b/src/components/WatchFolder/mappingList.tsx @@ -1,11 +1,16 @@ import React from 'react'; +import { WatchMapping } from 'types/watchFolder'; import { MappingEntry } from './mappingEntry'; import { MappingsContainer } from './styledComponents'; -export function MappingList({ mappings, handleRemoveWatchMapping }) { +interface Iprops { + mappings: WatchMapping[]; + handleRemoveWatchMapping: (value: WatchMapping) => void; +} + +export function MappingList({ mappings, handleRemoveWatchMapping }: Iprops) { return ( {mappings.map((mapping) => { - console.log(mapping); return ( Date: Sun, 19 Jun 2022 17:55:47 +0530 Subject: [PATCH 051/295] remove unnessary import --- src/pages/_app.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index ddf2833157a219685d055836edbfc23634ea31c7..612dc8da0e80adb471a0d9fa425e074b65c41bc7 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -19,8 +19,6 @@ import DialogBox from 'components/DialogBox'; import { styled, ThemeProvider } from '@mui/material/styles'; import darkThemeOptions from 'themes/darkThemeOptions'; import { CssBaseline } from '@mui/material'; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -// import * as types from 'styled-components/cssprop'; // need to css prop on styled component import { DialogBoxAttributes, SetDialogBoxAttributes } from 'types/dialogBox'; import { getFamilyPortalRedirectURL, From 1117534cc8a9db4c5bd915fa4db650175d924958 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sun, 19 Jun 2022 17:58:00 +0530 Subject: [PATCH 052/295] use shorthand --- src/pages/_app.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 612dc8da0e80adb471a0d9fa425e074b65c41bc7..f0d971c640cedf65a6dace5ea68f14dc9eab5bd4 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -281,12 +281,12 @@ export default function App({ Component, err }) { finishLoading, closeMessageDialog, setDialogMessage, - isFolderSyncRunning: isFolderSyncRunning, - setIsFolderSyncRunning: setIsFolderSyncRunning, - watchFolderView: watchFolderView, - setWatchFolderView: setWatchFolderView, - watchFolderFiles: watchFolderFiles, - setWatchFolderFiles: setWatchFolderFiles, + isFolderSyncRunning, + setIsFolderSyncRunning, + watchFolderView, + setWatchFolderView, + watchFolderFiles, + setWatchFolderFiles, }}> {loading ? ( From 99b5cce1c9f44a200353368743bd3162b247d510 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sun, 19 Jun 2022 18:07:55 +0530 Subject: [PATCH 053/295] rename watchService to watchFolderService --- src/components/UploadProgress/index.tsx | 7 ++++-- src/components/WatchFolder/index.tsx | 16 ++++++------- .../WatchFolder/mappingEntry/entryHeading.tsx | 4 ++-- src/components/pages/gallery/Upload.tsx | 6 ++--- src/services/upload/uploadManager.ts | 4 ++-- src/services/watchFolderService.ts | 23 ++++++++++--------- src/types/electron/index.ts | 10 ++++---- 7 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/components/UploadProgress/index.tsx b/src/components/UploadProgress/index.tsx index 71d839a7ff175ce1ea944daf2a4953c6e9490c27..2de22f3028ea4702349a78019e471fa8530a65d9 100644 --- a/src/components/UploadProgress/index.tsx +++ b/src/components/UploadProgress/index.tsx @@ -13,7 +13,7 @@ import { InProgressUpload, } from 'types/upload/ui'; import UploadProgressContext from 'contexts/uploadProgress'; -import watchService from 'services/watchFolderService'; +import watchFolderService from 'services/watchFolderService'; interface Props { open: boolean; @@ -45,7 +45,10 @@ export default function UploadProgress({ const [expanded, setExpanded] = useState(true); useEffect(() => { - if (appContext.isFolderSyncRunning && watchService.isUploadRunning()) { + if ( + appContext.isFolderSyncRunning && + watchFolderService.isUploadRunning() + ) { setExpanded(false); } }, [appContext.isFolderSyncRunning]); diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index 996c7e2e2d9aab713ef5f3acf776c145692c9cf7..a504a5d4a6ae4ae406ee8688e369fae165112d87 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -2,7 +2,7 @@ import { MappingList } from './mappingList'; import { NoMappingsContent } from './noMappingsContent'; import React, { useContext, useEffect, useState } from 'react'; import { Button, DialogActions, DialogContent } from '@mui/material'; -import watchService from 'services/watchFolderService'; +import watchFolderService from 'services/watchFolderService'; import { WatchMapping } from 'types/watchFolder'; import { AppContext } from 'pages/_app'; import constants from 'utils/strings/constants'; @@ -19,7 +19,7 @@ export default function WatchFolder({ open, onClose }: Iprops) { const appContext = useContext(AppContext); useEffect(() => { - setMappings(watchService.getWatchMappings()); + setMappings(watchFolderService.getWatchMappings()); }, []); useEffect(() => { @@ -35,7 +35,7 @@ export default function WatchFolder({ open, onClose }: Iprops) { for (let i = 0; i < folders.length; i++) { const folder: any = folders[i]; const path = (folder.path as string).replace(/\\/g, '/'); - if (await watchService.isFolder(path)) { + if (await watchFolderService.isFolder(path)) { await handleAddWatchMapping(path); } } @@ -46,23 +46,23 @@ export default function WatchFolder({ open, onClose }: Iprops) { }; const handleFolderSelection = async () => { - const folderPath = await watchService.selectFolder(); + const folderPath = await watchFolderService.selectFolder(); await handleAddWatchMapping(folderPath); }; const handleAddWatchMapping = async (inputFolderPath: string) => { if (inputFolderPath?.length > 0) { - await watchService.addWatchMapping( + await watchFolderService.addWatchMapping( inputFolderPath.substring(inputFolderPath.lastIndexOf('/') + 1), inputFolderPath ); - setMappings(watchService.getWatchMappings()); + setMappings(watchFolderService.getWatchMappings()); } }; const handleRemoveWatchMapping = async (mapping: WatchMapping) => { - await watchService.removeWatchMapping(mapping.collectionName); - setMappings(watchService.getWatchMappings()); + await watchFolderService.removeWatchMapping(mapping.collectionName); + setMappings(watchFolderService.getWatchMappings()); }; return ( diff --git a/src/components/WatchFolder/mappingEntry/entryHeading.tsx b/src/components/WatchFolder/mappingEntry/entryHeading.tsx index 1c9ce028d7145ae79dc4766dccd830d571602b81..fa8c52b467d80b857cc5f7d3d810e228499f9eb8 100644 --- a/src/components/WatchFolder/mappingEntry/entryHeading.tsx +++ b/src/components/WatchFolder/mappingEntry/entryHeading.tsx @@ -1,6 +1,6 @@ import React, { useContext } from 'react'; import { Typography } from '@mui/material'; -import watchService from 'services/watchFolderService'; +import watchFolderService from 'services/watchFolderService'; import { AppContext } from 'pages/_app'; import { SyncProgressIcon } from './syncProgressIcon'; import { FlexWrapper } from 'components/Container'; @@ -22,7 +22,7 @@ export function EntryHeading({ mapping }: Iprops) { {mapping.collectionName} {appContext.isFolderSyncRunning && - watchService.currentEvent?.collectionName === + watchFolderService.currentEvent?.collectionName === mapping.collectionName && } ); diff --git a/src/components/pages/gallery/Upload.tsx b/src/components/pages/gallery/Upload.tsx index 96e166a7b5622033e3557cfa1c4397b2108829b5..8e8674d498d8c5d99ba9be7d312a8dd0a1211832 100644 --- a/src/components/pages/gallery/Upload.tsx +++ b/src/components/pages/gallery/Upload.tsx @@ -24,7 +24,7 @@ import UploadTypeSelector from '../../UploadTypeSelector'; import Router from 'next/router'; import { isCanvasBlocked } from 'utils/upload/isCanvasBlocked'; import { downloadApp } from 'utils/common'; -import watchService from 'services/watchFolderService'; +import watchFolderService from 'services/watchFolderService'; import DiscFullIcon from '@mui/icons-material/DiscFull'; import { NotificationAttributes } from 'types/Notification'; import { @@ -128,7 +128,7 @@ export default function Upload(props: Props) { resumeDesktopUpload(type, electronFiles, collectionName); } ); - watchService.init( + watchFolderService.init( props.setElectronFiles, setCollectionName, props.syncWithRemote, @@ -380,7 +380,7 @@ export default function Upload(props: Props) { props.setUploadInProgress(false); props.syncWithRemote(); if (isElectron()) { - await watchService.allFileUploadsDone( + await watchFolderService.allFileUploadsDone( filesWithCollectionToUpload, collections ); diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index 121faf885d0cbb338ac28c5bdc4b46c87d9151fd..94ddf3778b5f0f78cec20c627d03e0538223a758 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -38,7 +38,7 @@ import uiService from './uiService'; import { logUploadInfo } from 'utils/upload'; import isElectron from 'is-electron'; import ImportService from 'services/importService'; -import watchService from 'services/watchFolderService'; +import watchFolderService from 'services/watchFolderService'; import { ProgressUpdater } from 'types/upload/ui'; const MAX_CONCURRENT_UPLOADS = 4; @@ -407,7 +407,7 @@ class UploadManager { UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL || fileUploadResult === UPLOAD_RESULT.ALREADY_UPLOADED ) { - await watchService.onFileUpload( + await watchFolderService.onFileUpload( fileWithCollection, uploadedFile ); diff --git a/src/services/watchFolderService.ts b/src/services/watchFolderService.ts index 16816cb7da1b533a682dcb4c5ef03b8c20eeb319..8ec0c21095cac516e5f27101ecb04e63eaf7c32d 100644 --- a/src/services/watchFolderService.ts +++ b/src/services/watchFolderService.ts @@ -9,7 +9,7 @@ import { logError } from 'utils/sentry'; import { EventQueueItem, WatchMapping } from 'types/watchFolder'; import { ElectronAPIsInterface } from 'types/electron'; -export class WatchService { +export class watchFolderService { ElectronAPIs: ElectronAPIsInterface; allElectronAPIsExist: boolean = false; eventQueue: EventQueueItem[] = []; @@ -22,7 +22,7 @@ export class WatchService { setCollectionName: (collectionName: string) => void; syncWithRemote: () => void; showProgressView: () => void; - setWatchServiceIsRunning: (isRunning: boolean) => void; + setwatchFolderServiceIsRunning: (isRunning: boolean) => void; constructor() { this.ElectronAPIs = (runningInBrowser() && @@ -38,14 +38,15 @@ export class WatchService { setElectronFiles: (files: ElectronFile[]) => void, setCollectionName: (collectionName: string) => void, syncWithRemote: () => void, - setWatchServiceIsRunning: (isRunning: boolean) => void + setwatchFolderServiceIsRunning: (isRunning: boolean) => void ) { if (this.allElectronAPIsExist) { try { this.setElectronFiles = setElectronFiles; this.setCollectionName = setCollectionName; this.syncWithRemote = syncWithRemote; - this.setWatchServiceIsRunning = setWatchServiceIsRunning; + this.setwatchFolderServiceIsRunning = + setwatchFolderServiceIsRunning; let mappings = this.getWatchMappings(); @@ -179,7 +180,7 @@ export class WatchService { setIsEventRunning(isEventRunning: boolean) { this.isEventRunning = isEventRunning; - this.setWatchServiceIsRunning(isEventRunning); + this.setwatchFolderServiceIsRunning(isEventRunning); } async runNextEvent() { @@ -462,7 +463,7 @@ export class WatchService { } async function diskFileAddedCallback( - instance: WatchService, + instance: watchFolderService, file: ElectronFile ) { try { @@ -487,7 +488,7 @@ async function diskFileAddedCallback( } async function diskFileRemovedCallback( - instance: WatchService, + instance: watchFolderService, filePath: string ) { try { @@ -512,7 +513,7 @@ async function diskFileRemovedCallback( } async function diskFolderRemovedCallback( - instance: WatchService, + instance: watchFolderService, folderPath: string ) { try { @@ -529,12 +530,12 @@ async function diskFolderRemovedCallback( } } -const runNextEventByInstance = async (w: WatchService) => { +const runNextEventByInstance = async (w: watchFolderService) => { await w.runNextEvent(); }; const hasMappingSameFolderPath = ( - w: WatchService, + w: watchFolderService, collectionName: string, folderPath: string ) => { @@ -545,4 +546,4 @@ const hasMappingSameFolderPath = ( return mapping.folderPath === folderPath; }; -export default new WatchService(); +export default new watchFolderService(); diff --git a/src/types/electron/index.ts b/src/types/electron/index.ts index 9851b43340144ab2f124a6a0ba22eaa49fa4c2fa..e33dee0e550ba600ebfa0d2c8b75eecfddd3fc3e 100644 --- a/src/types/electron/index.ts +++ b/src/types/electron/index.ts @@ -1,4 +1,4 @@ -import { WatchService } from 'services/watchFolderService'; +import { watchFolderService } from 'services/watchFolderService'; import { ElectronFile } from 'types/upload'; import { WatchMapping } from 'types/watchFolder'; @@ -47,17 +47,17 @@ export interface ElectronAPIsInterface { ) => Promise; removeWatchMapping: (collectionName: string) => Promise; registerWatcherFunctions: ( - WatchServiceInstance: WatchService, + watchFolderServiceInstance: watchFolderService, addFile: ( - WatchServiceInstance: WatchService, + watchFolderServiceInstance: watchFolderService, file: ElectronFile ) => Promise, removeFile: ( - WatchServiceInstance: WatchService, + watchFolderServiceInstance: watchFolderService, path: string ) => Promise, removeFolder: ( - WatchServiceInstance: WatchService, + watchFolderServiceInstance: watchFolderService, folderPath: string ) => Promise ) => void; From 4f16669acf5a86e51588f45c5b4bdda5ace65382 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sun, 19 Jun 2022 18:29:16 +0530 Subject: [PATCH 054/295] restruct postUploadAction --- src/constants/upload/index.ts | 1 + src/services/upload/uploadManager.ts | 124 ++++++++++++++++----------- src/services/upload/uploader.ts | 4 +- 3 files changed, 74 insertions(+), 55 deletions(-) diff --git a/src/constants/upload/index.ts b/src/constants/upload/index.ts index 2c9d7a4e6b3fe4ec5ba89c2fcaa5b681b9fde0ce..6056600e3e57e13027057f1f3c1112a42eb01cf9 100644 --- a/src/constants/upload/index.ts +++ b/src/constants/upload/index.ts @@ -40,6 +40,7 @@ export enum UPLOAD_RESULT { LARGER_THAN_AVAILABLE_STORAGE, UPLOADED, UPLOADED_WITH_STATIC_THUMBNAIL, + ADDED_SYMLINK, } export const MAX_FILE_SIZE_SUPPORTED = 4 * 1024 * 1024 * 1024; // 4 GB diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index 94ddf3778b5f0f78cec20c627d03e0538223a758..f711dae86f8cf4676dacffa9ff0af621777adf14 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -329,13 +329,12 @@ class UploadManager { this.existingFilesCollectionWise.get(collectionID) ?? []; const collection = this.collections.get(collectionID); fileWithCollection = { ...fileWithCollection, collection }; - const { fileUploadResult, uploadedFile, skipDecryption } = - await uploader( - worker, - existingFilesInCollection, - this.existingFiles, - fileWithCollection - ); + const { fileUploadResult, uploadedFile } = await uploader( + worker, + existingFilesInCollection, + this.existingFiles, + fileWithCollection + ); UIService.moveFileToResultList( fileWithCollection.localID, fileUploadResult @@ -344,7 +343,6 @@ class UploadManager { await this.postUploadTask( fileUploadResult, uploadedFile, - skipDecryption, fileWithCollection ); } @@ -353,66 +351,46 @@ class UploadManager { async postUploadTask( fileUploadResult: UPLOAD_RESULT, uploadedFile: EnteFile, - skipDecryption: boolean, fileWithCollection: FileWithCollection ) { try { + let decryptedFile: EnteFile; logUploadInfo(`uploadedFile ${JSON.stringify(uploadedFile)}`); - + this.updateElectronRemainingFiles(fileWithCollection); if ( - (fileUploadResult === UPLOAD_RESULT.UPLOADED || - fileUploadResult === - UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL) && - !skipDecryption + fileUploadResult === + UPLOAD_RESULT.LARGER_THAN_AVAILABLE_STORAGE || + fileUploadResult === UPLOAD_RESULT.TOO_LARGE || + fileUploadResult === UPLOAD_RESULT.UNSUPPORTED ) { - const decryptedFile = await decryptFile( - uploadedFile, - fileWithCollection.collection.key - ); - this.existingFiles.push(decryptedFile); - this.existingFiles = sortFiles(this.existingFiles); - await setLocalFiles(this.existingFiles); - this.setFiles(preservePhotoswipeProps(this.existingFiles)); - if ( - !this.existingFilesCollectionWise.has( - decryptedFile.collectionID - ) - ) { - this.existingFilesCollectionWise.set( - decryptedFile.collectionID, - [] - ); - } - this.existingFilesCollectionWise - .get(decryptedFile.collectionID) - .push(decryptedFile); - } - if ( + // no-op + } else if ( fileUploadResult === UPLOAD_RESULT.FAILED || fileUploadResult === UPLOAD_RESULT.BLOCKED ) { this.failedFiles.push(fileWithCollection); - } - - if (isElectron()) { - this.remainingFiles = this.remainingFiles.filter( - (file) => - !areFileWithCollectionsSame(file, fileWithCollection) - ); - ImportService.updatePendingUploads(this.remainingFiles); - - if ( - fileUploadResult === UPLOAD_RESULT.UPLOADED || - fileUploadResult === - UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL || - fileUploadResult === UPLOAD_RESULT.ALREADY_UPLOADED - ) { + } else if (fileUploadResult === UPLOAD_RESULT.ALREADY_UPLOADED) { + if (isElectron()) { await watchFolderService.onFileUpload( fileWithCollection, uploadedFile ); } + } else if ( + fileUploadResult === UPLOAD_RESULT.UPLOADED || + fileUploadResult === + UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL + ) { + decryptedFile = await decryptFile( + uploadedFile, + fileWithCollection.collection.key + ); + } else { + decryptedFile = uploadedFile; } + await this.updateExistingFiles(decryptedFile); + this.updateExistingCollections(decryptedFile); + await this.watchFolderCallback(fileWithCollection, uploadedFile); } catch (e) { logError(e, 'failed to do post file upload action'); logUploadInfo( @@ -423,6 +401,48 @@ class UploadManager { } } + private async watchFolderCallback( + fileWithCollection: FileWithCollection, + uploadedFile: EnteFile + ) { + if (isElectron()) { + await watchFolderService.onFileUpload( + fileWithCollection, + uploadedFile + ); + } + } + + private updateExistingCollections(decryptedFile: EnteFile) { + if (!this.existingFilesCollectionWise.has(decryptedFile.collectionID)) { + this.existingFilesCollectionWise.set( + decryptedFile.collectionID, + [] + ); + } + this.existingFilesCollectionWise + .get(decryptedFile.collectionID) + .push(decryptedFile); + } + + private async updateExistingFiles(decryptedFile: EnteFile) { + this.existingFiles.push(decryptedFile); + this.existingFiles = sortFiles(this.existingFiles); + await setLocalFiles(this.existingFiles); + this.setFiles(preservePhotoswipeProps(this.existingFiles)); + } + + private updateElectronRemainingFiles( + fileWithCollection: FileWithCollection + ) { + if (isElectron()) { + this.remainingFiles = this.remainingFiles.filter( + (file) => !areFileWithCollectionsSame(file, fileWithCollection) + ); + ImportService.updatePendingUploads(this.remainingFiles); + } + } + async retryFailedFiles() { await this.queueFilesForUpload(this.failedFiles, [ ...this.collections.values(), diff --git a/src/services/upload/uploader.ts b/src/services/upload/uploader.ts index c43012b0477bd17e3aba05cc095278e873c5af46..12365d9a78920e8587a729790af2feda8b08c235 100644 --- a/src/services/upload/uploader.ts +++ b/src/services/upload/uploader.ts @@ -20,7 +20,6 @@ import { addToCollection } from 'services/collectionService'; interface UploadResponse { fileUploadResult: UPLOAD_RESULT; uploadedFile?: EnteFile; - skipDecryption?: boolean; } export default async function uploader( worker: any, @@ -75,9 +74,8 @@ export default async function uploader( resultFile.collectionID = collection.id; await addToCollection(collection, [resultFile]); return { - fileUploadResult: UPLOAD_RESULT.UPLOADED, + fileUploadResult: UPLOAD_RESULT.ADDED_SYMLINK, uploadedFile: resultFile, - skipDecryption: true, }; } From 86d6bf934056c33900b146aebbf189091a3171b2 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sun, 19 Jun 2022 18:31:26 +0530 Subject: [PATCH 055/295] fix casing --- src/services/watchFolderService.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/services/watchFolderService.ts b/src/services/watchFolderService.ts index 8ec0c21095cac516e5f27101ecb04e63eaf7c32d..150568a56f4eb01c7e38266120ce190b6f955a68 100644 --- a/src/services/watchFolderService.ts +++ b/src/services/watchFolderService.ts @@ -22,7 +22,7 @@ export class watchFolderService { setCollectionName: (collectionName: string) => void; syncWithRemote: () => void; showProgressView: () => void; - setwatchFolderServiceIsRunning: (isRunning: boolean) => void; + setWatchFolderServiceIsRunning: (isRunning: boolean) => void; constructor() { this.ElectronAPIs = (runningInBrowser() && @@ -38,15 +38,15 @@ export class watchFolderService { setElectronFiles: (files: ElectronFile[]) => void, setCollectionName: (collectionName: string) => void, syncWithRemote: () => void, - setwatchFolderServiceIsRunning: (isRunning: boolean) => void + setWatchFolderServiceIsRunning: (isRunning: boolean) => void ) { if (this.allElectronAPIsExist) { try { this.setElectronFiles = setElectronFiles; this.setCollectionName = setCollectionName; this.syncWithRemote = syncWithRemote; - this.setwatchFolderServiceIsRunning = - setwatchFolderServiceIsRunning; + this.setWatchFolderServiceIsRunning = + setWatchFolderServiceIsRunning; let mappings = this.getWatchMappings(); @@ -180,7 +180,7 @@ export class watchFolderService { setIsEventRunning(isEventRunning: boolean) { this.isEventRunning = isEventRunning; - this.setwatchFolderServiceIsRunning(isEventRunning); + this.setWatchFolderServiceIsRunning(isEventRunning); } async runNextEvent() { From da90b22576ab327c10f72769215dad76d64c6a10 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sun, 19 Jun 2022 19:56:09 +0530 Subject: [PATCH 056/295] move event handler to seperate file --- src/components/UploadProgress/index.tsx | 2 +- src/components/WatchFolder/index.tsx | 2 +- .../WatchFolder/mappingEntry/entryHeading.tsx | 7 +- src/components/pages/gallery/Upload.tsx | 2 +- src/services/upload/uploadManager.ts | 2 +- .../watchFolder/watchFolderEventHandlers.ts | 78 +++++++++ .../{ => watchFolder}/watchFolderService.ts | 151 +++++------------- src/types/electron/index.ts | 17 +- 8 files changed, 131 insertions(+), 130 deletions(-) create mode 100644 src/services/watchFolder/watchFolderEventHandlers.ts rename src/services/{ => watchFolder}/watchFolderService.ts (81%) diff --git a/src/components/UploadProgress/index.tsx b/src/components/UploadProgress/index.tsx index 2de22f3028ea4702349a78019e471fa8530a65d9..9834daa80ee4cb5d5d8a546482a055d6520aeb24 100644 --- a/src/components/UploadProgress/index.tsx +++ b/src/components/UploadProgress/index.tsx @@ -13,7 +13,7 @@ import { InProgressUpload, } from 'types/upload/ui'; import UploadProgressContext from 'contexts/uploadProgress'; -import watchFolderService from 'services/watchFolderService'; +import watchFolderService from 'services/watchFolder/watchFolderService'; interface Props { open: boolean; diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index a504a5d4a6ae4ae406ee8688e369fae165112d87..bbaf1e14e3ad07e7f53415c002d09ca52428a4fc 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -2,7 +2,7 @@ import { MappingList } from './mappingList'; import { NoMappingsContent } from './noMappingsContent'; import React, { useContext, useEffect, useState } from 'react'; import { Button, DialogActions, DialogContent } from '@mui/material'; -import watchFolderService from 'services/watchFolderService'; +import watchFolderService from 'services/watchFolder/watchFolderService'; import { WatchMapping } from 'types/watchFolder'; import { AppContext } from 'pages/_app'; import constants from 'utils/strings/constants'; diff --git a/src/components/WatchFolder/mappingEntry/entryHeading.tsx b/src/components/WatchFolder/mappingEntry/entryHeading.tsx index fa8c52b467d80b857cc5f7d3d810e228499f9eb8..0e2f6d42c082281e32db24cd91f628362249b61a 100644 --- a/src/components/WatchFolder/mappingEntry/entryHeading.tsx +++ b/src/components/WatchFolder/mappingEntry/entryHeading.tsx @@ -1,6 +1,6 @@ import React, { useContext } from 'react'; import { Typography } from '@mui/material'; -import watchFolderService from 'services/watchFolderService'; +import watchFolderService from 'services/watchFolder/watchFolderService'; import { AppContext } from 'pages/_app'; import { SyncProgressIcon } from './syncProgressIcon'; import { FlexWrapper } from 'components/Container'; @@ -22,8 +22,9 @@ export function EntryHeading({ mapping }: Iprops) { {mapping.collectionName} {appContext.isFolderSyncRunning && - watchFolderService.currentEvent?.collectionName === - mapping.collectionName && } + watchFolderService.isMappingSyncing(mapping) && ( + + )} ); } diff --git a/src/components/pages/gallery/Upload.tsx b/src/components/pages/gallery/Upload.tsx index 8e8674d498d8c5d99ba9be7d312a8dd0a1211832..4db1d7d8f4fb1dfc32d78b6cd952157de20502a0 100644 --- a/src/components/pages/gallery/Upload.tsx +++ b/src/components/pages/gallery/Upload.tsx @@ -24,7 +24,7 @@ import UploadTypeSelector from '../../UploadTypeSelector'; import Router from 'next/router'; import { isCanvasBlocked } from 'utils/upload/isCanvasBlocked'; import { downloadApp } from 'utils/common'; -import watchFolderService from 'services/watchFolderService'; +import watchFolderService from 'services/watchFolder/watchFolderService'; import DiscFullIcon from '@mui/icons-material/DiscFull'; import { NotificationAttributes } from 'types/Notification'; import { diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index 94ddf3778b5f0f78cec20c627d03e0538223a758..a07997acea19685c8b1a3440723057fd07701de2 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -38,7 +38,7 @@ import uiService from './uiService'; import { logUploadInfo } from 'utils/upload'; import isElectron from 'is-electron'; import ImportService from 'services/importService'; -import watchFolderService from 'services/watchFolderService'; +import watchFolderService from 'services/watchFolder/watchFolderService'; import { ProgressUpdater } from 'types/upload/ui'; const MAX_CONCURRENT_UPLOADS = 4; diff --git a/src/services/watchFolder/watchFolderEventHandlers.ts b/src/services/watchFolder/watchFolderEventHandlers.ts new file mode 100644 index 0000000000000000000000000000000000000000..aef05f852c84ef54aaed3f9be09f5db9dfe0a127 --- /dev/null +++ b/src/services/watchFolder/watchFolderEventHandlers.ts @@ -0,0 +1,78 @@ +import { ElectronFile } from 'types/upload'; +import { EventQueueItem } from 'types/watchFolder'; +import { logError } from 'utils/sentry'; +import watchFolderService from './watchFolderService'; + +export async function diskFileAddedCallback(file: ElectronFile) { + try { + const collectionName = await watchFolderService.getCollectionName( + file.path + ); + + if (!collectionName) { + return; + } + + console.log('added (upload) to event queue', collectionName, file); + + const event: EventQueueItem = { + type: 'upload', + collectionName, + files: [file], + }; + watchFolderService.pushEvent(event); + } catch (e) { + logError(e, 'error while calling diskFileAddedCallback'); + } +} + +export async function diskFileRemovedCallback(filePath: string) { + try { + const collectionName = await watchFolderService.getCollectionName( + filePath + ); + + console.log('added (trash) to event queue', collectionName, filePath); + + if (!collectionName) { + return; + } + + const event: EventQueueItem = { + type: 'trash', + collectionName, + paths: [filePath], + }; + watchFolderService.pushEvent(event); + } catch (e) { + logError(e, 'error while calling diskFileRemovedCallback'); + } +} + +export async function diskFolderRemovedCallback(folderPath: string) { + try { + const collectionName = await watchFolderService.getCollectionName( + folderPath + ); + if (!collectionName) { + return; + } + + if (hasMappingSameFolderPath(collectionName, folderPath)) { + watchFolderService.pushTrashedDir(folderPath); + } + } catch (e) { + logError(e, 'error while calling diskFolderRemovedCallback'); + } +} + +const hasMappingSameFolderPath = ( + collectionName: string, + folderPath: string +) => { + const mappings = watchFolderService.getWatchMappings(); + const mapping = mappings.find( + (mapping) => mapping.collectionName === collectionName + ); + return mapping.folderPath === folderPath; +}; diff --git a/src/services/watchFolderService.ts b/src/services/watchFolder/watchFolderService.ts similarity index 81% rename from src/services/watchFolderService.ts rename to src/services/watchFolder/watchFolderService.ts index 150568a56f4eb01c7e38266120ce190b6f955a68..ecb3125605dde150c50d6d55b4948a5a7e4da86f 100644 --- a/src/services/watchFolderService.ts +++ b/src/services/watchFolder/watchFolderService.ts @@ -2,27 +2,32 @@ import { Collection } from 'types/collection'; import { EnteFile } from 'types/file'; import { ElectronFile, FileWithCollection } from 'types/upload'; import { runningInBrowser } from 'utils/common'; -import { removeFromCollection, syncCollections } from './collectionService'; -import { syncFiles } from './fileService'; -import debounce from 'debounce-promise'; +import { removeFromCollection, syncCollections } from '../collectionService'; +import { syncFiles } from '../fileService'; import { logError } from 'utils/sentry'; import { EventQueueItem, WatchMapping } from 'types/watchFolder'; import { ElectronAPIsInterface } from 'types/electron'; - -export class watchFolderService { - ElectronAPIs: ElectronAPIsInterface; - allElectronAPIsExist: boolean = false; - eventQueue: EventQueueItem[] = []; - currentEvent: EventQueueItem; - trashingDirQueue: string[] = []; - isEventRunning: boolean = false; - uploadRunning: boolean = false; - pathToIDMap = new Map(); - setElectronFiles: (files: ElectronFile[]) => void; - setCollectionName: (collectionName: string) => void; - syncWithRemote: () => void; - showProgressView: () => void; - setWatchFolderServiceIsRunning: (isRunning: boolean) => void; +import debounce from 'debounce-promise'; +import { + diskFileAddedCallback, + diskFileRemovedCallback, + diskFolderRemovedCallback, +} from './watchFolderEventHandlers'; + +class watchFolderService { + private ElectronAPIs: ElectronAPIsInterface; + private allElectronAPIsExist: boolean = false; + private eventQueue: EventQueueItem[] = []; + private currentEvent: EventQueueItem; + private trashingDirQueue: string[] = []; + private isEventRunning: boolean = false; + private uploadRunning: boolean = false; + private pathToIDMap = new Map(); + private setElectronFiles: (files: ElectronFile[]) => void; + private setCollectionName: (collectionName: string) => void; + private syncWithRemote: () => void; + private showProgressView: () => void; + private setWatchFolderServiceIsRunning: (isRunning: boolean) => void; constructor() { this.ElectronAPIs = (runningInBrowser() && @@ -76,6 +81,10 @@ export class watchFolderService { } } + isMappingSyncing(mapping: WatchMapping) { + return this.currentEvent?.collectionName === mapping.collectionName; + } + private uploadDiffOfFiles( mapping: WatchMapping, filesOnDisk: ElectronFile[] @@ -116,7 +125,7 @@ export class watchFolderService { } } - async filterOutDeletedMappings( + private async filterOutDeletedMappings( mappings: WatchMapping[] ): Promise { const notDeletedMappings = []; @@ -132,10 +141,18 @@ export class watchFolderService { return notDeletedMappings; } - setWatchFunctions() { + async pushEvent(event: EventQueueItem) { + this.eventQueue.push(event); + debounce(this.runNextEvent, 300); + } + + async pushTrashedDir(path: string) { + this.trashingDirQueue.push(path); + } + + private setWatchFunctions() { if (this.allElectronAPIsExist) { this.ElectronAPIs.registerWatcherFunctions( - this, diskFileAddedCallback, diskFileRemovedCallback, diskFolderRemovedCallback @@ -178,12 +195,12 @@ export class watchFolderService { return []; } - setIsEventRunning(isEventRunning: boolean) { + private setIsEventRunning(isEventRunning: boolean) { this.isEventRunning = isEventRunning; this.setWatchFolderServiceIsRunning(isEventRunning); } - async runNextEvent() { + private async runNextEvent() { console.log('runNextEvent mappings', this.getWatchMappings()); if (this.eventQueue.length === 0 || this.isEventRunning) { @@ -388,7 +405,7 @@ export class watchFolderService { } } - checkAndIgnoreIfFileEventsFromTrashedDir() { + private checkAndIgnoreIfFileEventsFromTrashedDir() { if (this.trashingDirQueue.length !== 0) { this.ignoreFileEventsFromTrashedDir(this.trashingDirQueue[0]); this.trashingDirQueue.shift(); @@ -398,7 +415,7 @@ export class watchFolderService { return false; } - ignoreFileEventsFromTrashedDir(trashingDir: string) { + private ignoreFileEventsFromTrashedDir(trashingDir: string) { this.eventQueue = this.eventQueue.filter((event) => event.paths.every((path) => !path.startsWith(trashingDir)) ); @@ -462,88 +479,4 @@ export class watchFolderService { } } -async function diskFileAddedCallback( - instance: watchFolderService, - file: ElectronFile -) { - try { - const collectionName = await instance.getCollectionName(file.path); - - if (!collectionName) { - return; - } - - console.log('added (upload) to event queue', collectionName, file); - - const event: EventQueueItem = { - type: 'upload', - collectionName, - files: [file], - }; - instance.eventQueue.push(event); - await debounce(runNextEventByInstance, 300)(instance); - } catch (e) { - logError(e, 'error while calling diskFileAddedCallback'); - } -} - -async function diskFileRemovedCallback( - instance: watchFolderService, - filePath: string -) { - try { - const collectionName = await instance.getCollectionName(filePath); - - console.log('added (trash) to event queue', collectionName, filePath); - - if (!collectionName) { - return; - } - - const event: EventQueueItem = { - type: 'trash', - collectionName, - paths: [filePath], - }; - instance.eventQueue.push(event); - await debounce(runNextEventByInstance, 300)(instance); - } catch (e) { - logError(e, 'error while calling diskFileRemovedCallback'); - } -} - -async function diskFolderRemovedCallback( - instance: watchFolderService, - folderPath: string -) { - try { - const collectionName = await instance.getCollectionName(folderPath); - if (!collectionName) { - return; - } - - if (hasMappingSameFolderPath(instance, collectionName, folderPath)) { - instance.trashingDirQueue.push(folderPath); - } - } catch (e) { - logError(e, 'error while calling diskFolderRemovedCallback'); - } -} - -const runNextEventByInstance = async (w: watchFolderService) => { - await w.runNextEvent(); -}; - -const hasMappingSameFolderPath = ( - w: watchFolderService, - collectionName: string, - folderPath: string -) => { - const mappings = w.getWatchMappings(); - const mapping = mappings.find( - (mapping) => mapping.collectionName === collectionName - ); - return mapping.folderPath === folderPath; -}; - export default new watchFolderService(); diff --git a/src/types/electron/index.ts b/src/types/electron/index.ts index e33dee0e550ba600ebfa0d2c8b75eecfddd3fc3e..944d259bfdb5a0171c0d18d7f2c92868378d34dd 100644 --- a/src/types/electron/index.ts +++ b/src/types/electron/index.ts @@ -1,4 +1,3 @@ -import { watchFolderService } from 'services/watchFolderService'; import { ElectronFile } from 'types/upload'; import { WatchMapping } from 'types/watchFolder'; @@ -47,19 +46,9 @@ export interface ElectronAPIsInterface { ) => Promise; removeWatchMapping: (collectionName: string) => Promise; registerWatcherFunctions: ( - watchFolderServiceInstance: watchFolderService, - addFile: ( - watchFolderServiceInstance: watchFolderService, - file: ElectronFile - ) => Promise, - removeFile: ( - watchFolderServiceInstance: watchFolderService, - path: string - ) => Promise, - removeFolder: ( - watchFolderServiceInstance: watchFolderService, - folderPath: string - ) => Promise + addFile: (file: ElectronFile) => Promise, + removeFile: (path: string) => Promise, + removeFolder: (folderPath: string) => Promise ) => void; doesFolderExists: (dirPath: string) => Promise; clearElectronStore: () => void; From 8e95b80a4e472e10da59bd7a9d1402fbb8967c90 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Sun, 19 Jun 2022 20:31:12 +0530 Subject: [PATCH 057/295] bind instance on next event run --- src/services/watchFolder/watchFolderService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/watchFolder/watchFolderService.ts b/src/services/watchFolder/watchFolderService.ts index ecb3125605dde150c50d6d55b4948a5a7e4da86f..dbba1a750eaab2e02199c9b435303b87f28314eb 100644 --- a/src/services/watchFolder/watchFolderService.ts +++ b/src/services/watchFolder/watchFolderService.ts @@ -143,7 +143,7 @@ class watchFolderService { async pushEvent(event: EventQueueItem) { this.eventQueue.push(event); - debounce(this.runNextEvent, 300); + debounce(this.runNextEvent.bind(this), 300)(); } async pushTrashedDir(path: string) { From c3bb0f22f173ae3e2ec9fe7fd06a1cdd9f9cc37c Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Sun, 19 Jun 2022 21:10:07 +0530 Subject: [PATCH 058/295] change param to id of remove from collection --- src/services/collectionService.ts | 6 +++--- src/services/watchFolder/watchFolderService.ts | 2 +- src/utils/collection/index.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/services/collectionService.ts b/src/services/collectionService.ts index 3d6b9a84c3985f80ef33ea941a09ba6797eecceb..74a4efd0c679ebd9caaf1e150ca521fa5c27bf6d 100644 --- a/src/services/collectionService.ts +++ b/src/services/collectionService.ts @@ -353,7 +353,7 @@ export const removeFromFavorites = async (file: EnteFile) => { if (!favCollection) { throw Error(CustomError.FAV_COLLECTION_MISSING); } - await removeFromCollection(favCollection, [file]); + await removeFromCollection(favCollection.id, [file]); } catch (e) { logError(e, 'remove from favorite failed'); } @@ -464,13 +464,13 @@ const encryptWithNewCollectionKey = async ( return fileKeysEncryptedWithNewCollection; }; export const removeFromCollection = async ( - collection: Collection, + collectionID: number, files: EnteFile[] ) => { try { const token = getToken(); const request: RemoveFromCollectionRequest = { - collectionID: collection.id, + collectionID: collectionID, fileIDs: files.map((file) => file.id), }; diff --git a/src/services/watchFolder/watchFolderService.ts b/src/services/watchFolder/watchFolderService.ts index dbba1a750eaab2e02199c9b435303b87f28314eb..d55b0199082b51acb753c605e5818d98014f644b 100644 --- a/src/services/watchFolder/watchFolderService.ts +++ b/src/services/watchFolder/watchFolderService.ts @@ -399,7 +399,7 @@ class watchFolderService { ); }); - await removeFromCollection(collection, filesToTrash); + await removeFromCollection(collection.id, filesToTrash); } catch (e) { logError(e, 'error while trashing by IDs'); } diff --git a/src/utils/collection/index.ts b/src/utils/collection/index.ts index efe3a69356c06a8af7b09b10b9caf1fe3a98469c..2e377f2edcdddaa4c015d1b73b4ad354a0141f07 100644 --- a/src/utils/collection/index.ts +++ b/src/utils/collection/index.ts @@ -56,7 +56,7 @@ export async function handleCollectionOps( ); break; case COLLECTION_OPS_TYPE.REMOVE: - await removeFromCollection(collection, selectedFiles); + await removeFromCollection(collection.id, selectedFiles); break; case COLLECTION_OPS_TYPE.RESTORE: await restoreToCollection(collection, selectedFiles); From 380768c4c72b6fb143b012f4651ad533e10e0c99 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Sun, 19 Jun 2022 21:28:07 +0530 Subject: [PATCH 059/295] refactor --- src/components/WatchFolder/index.tsx | 2 +- .../watchFolder/watchFolderService.ts | 37 ++++++++++--------- src/types/electron/index.ts | 2 +- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index bbaf1e14e3ad07e7f53415c002d09ca52428a4fc..2cf3beaf38628006a1280eaedee63c9a32e43bba 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -61,7 +61,7 @@ export default function WatchFolder({ open, onClose }: Iprops) { }; const handleRemoveWatchMapping = async (mapping: WatchMapping) => { - await watchFolderService.removeWatchMapping(mapping.collectionName); + await watchFolderService.removeWatchMapping(mapping.folderPath); setMappings(watchFolderService.getWatchMappings()); }; diff --git a/src/services/watchFolder/watchFolderService.ts b/src/services/watchFolder/watchFolderService.ts index d55b0199082b51acb753c605e5818d98014f644b..c5739a394b9856e26f07d6cbfc6e760e5f03d18e 100644 --- a/src/services/watchFolder/watchFolderService.ts +++ b/src/services/watchFolder/watchFolderService.ts @@ -2,8 +2,11 @@ import { Collection } from 'types/collection'; import { EnteFile } from 'types/file'; import { ElectronFile, FileWithCollection } from 'types/upload'; import { runningInBrowser } from 'utils/common'; -import { removeFromCollection, syncCollections } from '../collectionService'; -import { syncFiles } from '../fileService'; +import { + getLocalCollections, + removeFromCollection, +} from '../collectionService'; +import { getLocalFiles } from '../fileService'; import { logError } from 'utils/sentry'; import { EventQueueItem, WatchMapping } from 'types/watchFolder'; import { ElectronAPIsInterface } from 'types/electron'; @@ -173,10 +176,10 @@ class watchFolderService { } } - async removeWatchMapping(collectionName: string) { + async removeWatchMapping(folderPath: string) { if (this.allElectronAPIsExist) { try { - await this.ElectronAPIs.removeWatchMapping(collectionName); + await this.ElectronAPIs.removeWatchMapping(folderPath); } catch (e) { logError(e, 'error while removing watch mapping'); } @@ -213,7 +216,9 @@ class watchFolderService { if (event.type === 'upload') { this.processUploadEvent(); } else { - this.processTrashEvent(); + await this.processTrashEvent(); + this.setIsEventRunning(false); + this.runNextEvent(); } } @@ -282,19 +287,22 @@ class watchFolderService { if (mapping) { mapping.files = [...mapping.files, ...uploadedFiles]; this.ElectronAPIs.setWatchMappings(mappings); - this.syncWithRemote(); } } - this.setIsEventRunning(false); - this.uploadRunning = false; - this.runNextEvent(); + this.runPostUploadsAction(); } catch (e) { logError(e, 'error while running all file uploads done'); } } } + private runPostUploadsAction() { + this.setIsEventRunning(false); + this.uploadRunning = false; + this.runNextEvent(); + } + private handleUploadedFile( fileWithCollection: FileWithCollection, uploadedFiles: { path: string; id: number }[] @@ -340,7 +348,6 @@ class watchFolderService { private async processTrashEvent() { try { if (this.checkAndIgnoreIfFileEventsFromTrashedDir()) { - this.runNextEvent(); return; } @@ -365,10 +372,6 @@ class watchFolderService { (file) => !filePathsToRemove.has(file.path) ); this.ElectronAPIs.setWatchMappings(mappings); - this.syncWithRemote(); - - this.setIsEventRunning(false); - this.runNextEvent(); } catch (e) { logError(e, 'error while running next trash'); } @@ -379,14 +382,14 @@ class watchFolderService { collectionName: string ) { try { - const collections = await syncCollections(); + const collections = await getLocalCollections(); const collection = collections.find( (collection) => collection.name === collectionName ); if (!collection) { return; } - const files = await syncFiles(collections, () => {}); + const files = await getLocalFiles(); const idSet = new Set(); for (const file of toTrashFiles) { @@ -400,6 +403,7 @@ class watchFolderService { }); await removeFromCollection(collection.id, filesToTrash); + this.syncWithRemote(); } catch (e) { logError(e, 'error while trashing by IDs'); } @@ -409,7 +413,6 @@ class watchFolderService { if (this.trashingDirQueue.length !== 0) { this.ignoreFileEventsFromTrashedDir(this.trashingDirQueue[0]); this.trashingDirQueue.shift(); - this.setIsEventRunning(false); return true; } return false; diff --git a/src/types/electron/index.ts b/src/types/electron/index.ts index 944d259bfdb5a0171c0d18d7f2c92868378d34dd..36e3b1e11d173d940185484ed8633fd1380bb4d7 100644 --- a/src/types/electron/index.ts +++ b/src/types/electron/index.ts @@ -44,7 +44,7 @@ export interface ElectronAPIsInterface { collectionName: string, folderPath: string ) => Promise; - removeWatchMapping: (collectionName: string) => Promise; + removeWatchMapping: (folderPath: string) => Promise; registerWatcherFunctions: ( addFile: (file: ElectronFile) => Promise, removeFile: (path: string) => Promise, From 59e8112bd235ed771d9f56648ed6bdd0ecf3b3a5 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Tue, 21 Jun 2022 14:02:20 +0530 Subject: [PATCH 060/295] persist file paths for uploaded files --- src/services/upload/uploadManager.ts | 70 ++++++++++++++++------------ src/services/upload/uploader.ts | 49 ++++++++++++++++++- src/types/file/index.ts | 1 + src/types/upload/index.ts | 3 +- src/utils/file/index.ts | 25 +++++++++- src/utils/upload/index.ts | 18 ++++++- 6 files changed, 129 insertions(+), 37 deletions(-) diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index a07997acea19685c8b1a3440723057fd07701de2..d546e09be698433ca659cad382d27a4f8c6b99b3 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -19,7 +19,7 @@ import UIService from './uiService'; import UploadService from './uploadService'; import { CustomError } from 'utils/error'; import { Collection } from 'types/collection'; -import { EnteFile } from 'types/file'; +import { EnteFile, FileMagicMetadata } from 'types/file'; import { FileWithCollection, MetadataAndFileTypeInfo, @@ -40,6 +40,7 @@ import isElectron from 'is-electron'; import ImportService from 'services/importService'; import watchFolderService from 'services/watchFolder/watchFolderService'; import { ProgressUpdater } from 'types/upload/ui'; +import { NEW_FILE_MAGIC_METADATA } from 'types/magicMetadata'; const MAX_CONCURRENT_UPLOADS = 4; const FILE_UPLOAD_COMPLETED = 100; @@ -229,38 +230,44 @@ class UploadManager { UIService.reset(mediaFiles.length); for (const { file, localID, collectionID } of mediaFiles) { try { - const { fileTypeInfo, metadata } = await (async () => { - if (file.size >= MAX_FILE_SIZE_SUPPORTED) { - logUploadInfo( - `${getFileNameSize( - file - )} rejected because of large size` - ); - - return { fileTypeInfo: null, metadata: null }; - } - const fileTypeInfo = await UploadService.getFileType( - file - ); - if (fileTypeInfo.fileType === FILE_TYPE.OTHERS) { + const { fileTypeInfo, metadata, magicMetadata } = + await (async () => { + if (file.size >= MAX_FILE_SIZE_SUPPORTED) { + logUploadInfo( + `${getFileNameSize( + file + )} rejected because of large size` + ); + + return { fileTypeInfo: null, metadata: null }; + } + const fileTypeInfo = + await UploadService.getFileType(file); + if (fileTypeInfo.fileType === FILE_TYPE.OTHERS) { + logUploadInfo( + `${getFileNameSize( + file + )} rejected because of unknown file format` + ); + return { fileTypeInfo, metadata: null }; + } logUploadInfo( - `${getFileNameSize( - file - )} rejected because of unknown file format` + ` extracting ${getFileNameSize(file)} metadata` ); - return { fileTypeInfo, metadata: null }; - } - logUploadInfo( - ` extracting ${getFileNameSize(file)} metadata` - ); - const metadata = - (await UploadService.extractFileMetadata( - file, - collectionID, - fileTypeInfo - )) || null; - return { fileTypeInfo, metadata }; - })(); + const metadata = + (await UploadService.extractFileMetadata( + file, + collectionID, + fileTypeInfo + )) || null; + const magicMetadata = { + ...NEW_FILE_MAGIC_METADATA, + data: { + filePaths: [(file as any).path as string], + }, + } as FileMagicMetadata; + return { fileTypeInfo, metadata, magicMetadata }; + })(); logUploadInfo( `metadata extraction successful${getFileNameSize( @@ -270,6 +277,7 @@ class UploadManager { this.metadataAndFileTypeInfoMap.set(localID, { fileTypeInfo: fileTypeInfo && { ...fileTypeInfo }, metadata: metadata && { ...metadata }, + magicMetadata: magicMetadata && { ...magicMetadata }, }); UIService.increaseFileUploaded(); } catch (e) { diff --git a/src/services/upload/uploader.ts b/src/services/upload/uploader.ts index c43012b0477bd17e3aba05cc095278e873c5af46..91e69932574be97031abd28510eee89ff4858aa5 100644 --- a/src/services/upload/uploader.ts +++ b/src/services/upload/uploader.ts @@ -1,9 +1,10 @@ -import { EnteFile } from 'types/file'; +import { EnteFile, FileMagicMetadata } from 'types/file'; import { handleUploadError, CustomError } from 'utils/error'; import { logError } from 'utils/sentry'; import { findSameFileInCollection, findSameFileInOtherCollection, + getMergedMagicMetadataFilePaths, shouldDedupeAcrossCollection, } from 'utils/upload'; import UploadHttpClient from './uploadHttpClient'; @@ -16,12 +17,36 @@ import { logUploadInfo } from 'utils/upload'; import { convertBytesToHumanReadable } from 'utils/billing'; import { sleep } from 'utils/common'; import { addToCollection } from 'services/collectionService'; +import { updateMagicMetadataProps } from 'utils/magicMetadata'; +import { updateFileMagicMetadata } from 'services/fileService'; +import { NEW_FILE_MAGIC_METADATA } from 'types/magicMetadata'; +import { getFileKey } from 'utils/file'; interface UploadResponse { fileUploadResult: UPLOAD_RESULT; uploadedFile?: EnteFile; skipDecryption?: boolean; } + +const updateMagicMetadata = async ( + file: EnteFile, + magicMetadata: FileMagicMetadata, + collectionKey: string +) => { + magicMetadata.data.filePaths = getMergedMagicMetadataFilePaths( + file.magicMetadata, + magicMetadata + ); + file.key = await getFileKey(file, collectionKey); + const updatedMagicMetadata = await updateMagicMetadataProps( + file.magicMetadata ?? NEW_FILE_MAGIC_METADATA, + file.key, + { filePaths: magicMetadata.data.filePaths } + ); + file.magicMetadata = updatedMagicMetadata; + await updateFileMagicMetadata([file]); +}; + export default async function uploader( worker: any, existingFilesInCollection: EnteFile[], @@ -36,7 +61,7 @@ export default async function uploader( logUploadInfo(`uploader called for ${fileNameSize}`); UIService.setFileProgress(localID, 0); await sleep(0); - const { fileTypeInfo, metadata } = + const { fileTypeInfo, metadata, magicMetadata } = UploadService.getFileMetadataAndFileTypeInfo(localID); try { const fileSize = UploadService.getAssetSize(uploadAsset); @@ -56,6 +81,11 @@ export default async function uploader( ); if (sameFileInSameCollection) { logUploadInfo(`skipped upload for ${fileNameSize}`); + await updateMagicMetadata( + sameFileInSameCollection, + magicMetadata, + fileWithCollection.collection.key + ); return { fileUploadResult: UPLOAD_RESULT.ALREADY_UPLOADED, uploadedFile: sameFileInSameCollection, @@ -74,6 +104,11 @@ export default async function uploader( const resultFile = Object.assign({}, sameFileInOtherCollection); resultFile.collectionID = collection.id; await addToCollection(collection, [resultFile]); + await updateMagicMetadata( + resultFile, + magicMetadata, + fileWithCollection.collection.key + ); return { fileUploadResult: UPLOAD_RESULT.UPLOADED, uploadedFile: resultFile, @@ -91,6 +126,11 @@ export default async function uploader( metadata ); if (sameFileInOtherCollection) { + await updateMagicMetadata( + sameFileInOtherCollection, + magicMetadata, + fileWithCollection.collection.key + ); return { fileUploadResult: UPLOAD_RESULT.ALREADY_UPLOADED, uploadedFile: sameFileInOtherCollection, @@ -136,6 +176,11 @@ export default async function uploader( UIService.increaseFileUploaded(); logUploadInfo(`${fileNameSize} successfully uploaded`); + await updateMagicMetadata( + uploadedFile, + magicMetadata, + fileWithCollection.collection.key + ); return { fileUploadResult: metadata.hasStaticThumbnail ? UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL diff --git a/src/types/file/index.ts b/src/types/file/index.ts index b55afbbbf327b9f746ecf612edad4bb9e12e7136..1bc7a8d0ab2acc23841874de93064bbeb8e477b0 100644 --- a/src/types/file/index.ts +++ b/src/types/file/index.ts @@ -9,6 +9,7 @@ export interface fileAttribute { export interface FileMagicMetadataProps { visibility?: VISIBILITY_STATE; + filePaths?: string[]; } export interface FileMagicMetadata extends Omit { diff --git a/src/types/upload/index.ts b/src/types/upload/index.ts index 076ac7fff8d2826b493e09e75f70f163f486b71a..0f7716bef24f883734a43a87f1ed49874c76ed82 100644 --- a/src/types/upload/index.ts +++ b/src/types/upload/index.ts @@ -1,6 +1,6 @@ import { FILE_TYPE } from 'constants/file'; import { Collection } from 'types/collection'; -import { fileAttribute } from 'types/file'; +import { fileAttribute, FileMagicMetadata } from 'types/file'; export interface DataStream { stream: ReadableStream; @@ -92,6 +92,7 @@ export interface FileWithCollection extends UploadAsset { export interface MetadataAndFileTypeInfo { metadata: Metadata; fileTypeInfo: FileTypeInfo; + magicMetadata: FileMagicMetadata; } export type MetadataAndFileTypeInfoMap = Map; diff --git a/src/utils/file/index.ts b/src/utils/file/index.ts index 8be54c37f6e8e91aba15b0fec23bd503e7960818..f65571ceec31dd566cc586a676311ab092abf254 100644 --- a/src/utils/file/index.ts +++ b/src/utils/file/index.ts @@ -274,14 +274,20 @@ export async function decryptFile(file: EnteFile, collectionKey: string) { encryptedMetadata.decryptionHeader, file.key ); - if (file.magicMetadata?.data) { + if ( + file.magicMetadata?.data && + typeof file.magicMetadata.data === 'string' + ) { file.magicMetadata.data = await worker.decryptMetadata( file.magicMetadata.data, file.magicMetadata.header, file.key ); } - if (file.pubMagicMetadata?.data) { + if ( + file.pubMagicMetadata?.data && + typeof file.pubMagicMetadata.data === 'string' + ) { file.pubMagicMetadata.data = await worker.decryptMetadata( file.pubMagicMetadata.data, file.pubMagicMetadata.header, @@ -295,6 +301,21 @@ export async function decryptFile(file: EnteFile, collectionKey: string) { } } +export async function getFileKey(file: EnteFile, collectionKey: string) { + try { + const worker = await new CryptoWorker(); + file.key = await worker.decryptB64( + file.encryptedKey, + file.keyDecryptionNonce, + collectionKey + ); + return file.key; + } catch (e) { + logError(e, 'get file key failed'); + throw e; + } +} + export const preservePhotoswipeProps = (newFiles: EnteFile[]) => (currentFiles: EnteFile[]): EnteFile[] => { diff --git a/src/utils/upload/index.ts b/src/utils/upload/index.ts index 71a27f47bcd62445a18cafc20d51502bf6cfe843..a002c29e6010b872afe7b6d68954fdeb38104bc8 100644 --- a/src/utils/upload/index.ts +++ b/src/utils/upload/index.ts @@ -1,5 +1,5 @@ import { ElectronFile, FileWithCollection, Metadata } from 'types/upload'; -import { EnteFile } from 'types/file'; +import { EnteFile, FileMagicMetadata } from 'types/file'; import { convertBytesToHumanReadable } from 'utils/billing'; import { formatDateTime } from 'utils/file'; import { getLogs, saveLogLine } from 'utils/storage'; @@ -141,3 +141,19 @@ export function areFileWithCollectionsSame( ): boolean { return firstFile.localID === secondFile.localID; } + +export function getMergedMagicMetadataFilePaths( + oldMetadata: FileMagicMetadata, + newMetadata: FileMagicMetadata +): string[] { + if (!oldMetadata || !oldMetadata.data.filePaths) { + return newMetadata.data.filePaths; + } + const mergedMetadataFilePaths = [...oldMetadata.data.filePaths]; + newMetadata.data.filePaths.forEach((newMetadataFilePath) => { + if (!mergedMetadataFilePaths.includes(newMetadataFilePath)) { + mergedMetadataFilePaths.push(newMetadataFilePath); + } + }); + return mergedMetadataFilePaths; +} From 9c6ae4e9063b76fb79926c2b0619c072e151b231 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Wed, 22 Jun 2022 10:14:51 +0530 Subject: [PATCH 061/295] added functionality to handle multiple folders --- src/components/WatchFolder/index.tsx | 3 +- .../watchFolder/watchFolderEventHandlers.ts | 43 +++++----- .../watchFolder/watchFolderService.ts | 79 +++++++++++++------ src/types/electron/index.ts | 3 +- src/types/watchFolder/index.ts | 4 +- 5 files changed, 78 insertions(+), 54 deletions(-) diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index 2cf3beaf38628006a1280eaedee63c9a32e43bba..8bb2cd2345eaf158167c6d2f4de0ba83e70060b2 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -54,7 +54,8 @@ export default function WatchFolder({ open, onClose }: Iprops) { if (inputFolderPath?.length > 0) { await watchFolderService.addWatchMapping( inputFolderPath.substring(inputFolderPath.lastIndexOf('/') + 1), - inputFolderPath + inputFolderPath, + true ); setMappings(watchFolderService.getWatchMappings()); } diff --git a/src/services/watchFolder/watchFolderEventHandlers.ts b/src/services/watchFolder/watchFolderEventHandlers.ts index aef05f852c84ef54aaed3f9be09f5db9dfe0a127..a20c013163d567204875063fdd88427c787fdb0d 100644 --- a/src/services/watchFolder/watchFolderEventHandlers.ts +++ b/src/services/watchFolder/watchFolderEventHandlers.ts @@ -5,11 +5,12 @@ import watchFolderService from './watchFolderService'; export async function diskFileAddedCallback(file: ElectronFile) { try { - const collectionName = await watchFolderService.getCollectionName( - file.path - ); + const { collectionName, folderPath } = + (await watchFolderService.getCollectionNameAndFolderPath( + file.path + )) ?? {}; - if (!collectionName) { + if (!folderPath) { return; } @@ -18,6 +19,7 @@ export async function diskFileAddedCallback(file: ElectronFile) { const event: EventQueueItem = { type: 'upload', collectionName, + folderPath, files: [file], }; watchFolderService.pushEvent(event); @@ -28,19 +30,20 @@ export async function diskFileAddedCallback(file: ElectronFile) { export async function diskFileRemovedCallback(filePath: string) { try { - const collectionName = await watchFolderService.getCollectionName( - filePath - ); - + const { collectionName, folderPath } = + (await watchFolderService.getCollectionNameAndFolderPath( + filePath + )) ?? {}; console.log('added (trash) to event queue', collectionName, filePath); - if (!collectionName) { + if (!folderPath) { return; } const event: EventQueueItem = { type: 'trash', collectionName, + folderPath, paths: [filePath], }; watchFolderService.pushEvent(event); @@ -51,28 +54,18 @@ export async function diskFileRemovedCallback(filePath: string) { export async function diskFolderRemovedCallback(folderPath: string) { try { - const collectionName = await watchFolderService.getCollectionName( - folderPath - ); - if (!collectionName) { + const { folderPath: mappedFolderPath } = + (await watchFolderService.getCollectionNameAndFolderPath( + folderPath + )) ?? {}; + if (!mappedFolderPath) { return; } - if (hasMappingSameFolderPath(collectionName, folderPath)) { + if (mappedFolderPath === folderPath) { watchFolderService.pushTrashedDir(folderPath); } } catch (e) { logError(e, 'error while calling diskFolderRemovedCallback'); } } - -const hasMappingSameFolderPath = ( - collectionName: string, - folderPath: string -) => { - const mappings = watchFolderService.getWatchMappings(); - const mapping = mappings.find( - (mapping) => mapping.collectionName === collectionName - ); - return mapping.folderPath === folderPath; -}; diff --git a/src/services/watchFolder/watchFolderService.ts b/src/services/watchFolder/watchFolderService.ts index c5739a394b9856e26f07d6cbfc6e760e5f03d18e..15407fa300bbacb4d39951a26cec9ae9649de93d 100644 --- a/src/services/watchFolder/watchFolderService.ts +++ b/src/services/watchFolder/watchFolderService.ts @@ -29,7 +29,6 @@ class watchFolderService { private setElectronFiles: (files: ElectronFile[]) => void; private setCollectionName: (collectionName: string) => void; private syncWithRemote: () => void; - private showProgressView: () => void; private setWatchFolderServiceIsRunning: (isRunning: boolean) => void; constructor() { @@ -85,7 +84,7 @@ class watchFolderService { } isMappingSyncing(mapping: WatchMapping) { - return this.currentEvent?.collectionName === mapping.collectionName; + return this.currentEvent?.folderPath === mapping.folderPath; } private uploadDiffOfFiles( @@ -99,12 +98,17 @@ class watchFolderService { }); if (filesToUpload.length > 0) { - const event: EventQueueItem = { - type: 'upload', - collectionName: mapping.collectionName, - files: filesToUpload, - }; - this.eventQueue.push(event); + for (const file of filesToUpload) { + const event: EventQueueItem = { + type: 'upload', + collectionName: mapping.hasMultipleFolders + ? this.getParentFolderName(file.path) + : mapping.collectionName, + folderPath: mapping.folderPath, + files: [file], + }; + this.eventQueue.push(event); + } } } @@ -119,12 +123,17 @@ class watchFolderService { }); if (filesToRemove.length > 0) { - const event: EventQueueItem = { - type: 'trash', - collectionName: mapping.collectionName, - paths: filesToRemove.map((file) => file.path), - }; - this.eventQueue.push(event); + for (const file of filesToRemove) { + const event: EventQueueItem = { + type: 'trash', + collectionName: mapping.hasMultipleFolders + ? this.getParentFolderName(file.path) + : mapping.collectionName, + folderPath: mapping.folderPath, + paths: [file.path], + }; + this.eventQueue.push(event); + } } } @@ -163,12 +172,17 @@ class watchFolderService { } } - async addWatchMapping(collectionName: string, folderPath: string) { + async addWatchMapping( + collectionName: string, + folderPath: string, + hasMultipleFolders: boolean + ) { if (this.allElectronAPIsExist) { try { await this.ElectronAPIs.addWatchMapping( collectionName, - folderPath + folderPath, + hasMultipleFolders ); } catch (e) { logError(e, 'error while adding watch mapping'); @@ -204,7 +218,7 @@ class watchFolderService { } private async runNextEvent() { - console.log('runNextEvent mappings', this.getWatchMappings()); + console.log('mappings', this.getWatchMappings()); if (this.eventQueue.length === 0 || this.isEventRunning) { return; @@ -213,6 +227,7 @@ class watchFolderService { this.setIsEventRunning(true); const event = this.clubSameCollectionEvents(); this.currentEvent = event; + console.log('running event', event); if (event.type === 'upload') { this.processUploadEvent(); } else { @@ -281,8 +296,7 @@ class watchFolderService { const mappings = this.getWatchMappings(); const mapping = mappings.find( (mapping) => - mapping.collectionName === - this.currentEvent.collectionName + mapping.folderPath === this.currentEvent.folderPath ); if (mapping) { mapping.files = [...mapping.files, ...uploadedFiles]; @@ -351,12 +365,12 @@ class watchFolderService { return; } - const { collectionName, paths } = this.currentEvent; + const { collectionName, folderPath, paths } = this.currentEvent; const filePathsToRemove = new Set(paths); const mappings = this.getWatchMappings(); const mappingIdx = mappings.findIndex( - (mapping) => mapping.collectionName === collectionName + (mapping) => mapping.folderPath === folderPath ); if (mappingIdx === -1) { return; @@ -424,24 +438,37 @@ class watchFolderService { ); } - async getCollectionName(filePath: string) { + async getCollectionNameAndFolderPath(filePath: string) { try { const mappings = this.getWatchMappings(); - const collectionName = mappings.find((mapping) => + const mapping = mappings.find((mapping) => filePath.startsWith(mapping.folderPath + '/') - )?.collectionName; + ); - if (!collectionName) { + if (!mapping) { return null; } - return collectionName; + return { + collectionName: mapping.hasMultipleFolders + ? this.getParentFolderName(filePath) + : mapping.collectionName, + folderPath: mapping.folderPath, + }; } catch (e) { logError(e, 'error while getting collection name'); } } + private getParentFolderName(filePath: string) { + const folderPath = filePath.substring(0, filePath.lastIndexOf('/')); + const folderName = folderPath.substring( + folderPath.lastIndexOf('/') + 1 + ); + return folderName; + } + async selectFolder(): Promise { try { const folderPath = await this.ElectronAPIs.selectRootDirectory(); diff --git a/src/types/electron/index.ts b/src/types/electron/index.ts index 36e3b1e11d173d940185484ed8633fd1380bb4d7..893b0174dbc1baa5ee82687badea8cde489cdcb2 100644 --- a/src/types/electron/index.ts +++ b/src/types/electron/index.ts @@ -42,7 +42,8 @@ export interface ElectronAPIsInterface { setWatchMappings: (watchMappings: WatchMapping[]) => void; addWatchMapping: ( collectionName: string, - folderPath: string + folderPath: string, + hasMultipleFolders: boolean ) => Promise; removeWatchMapping: (folderPath: string) => Promise; registerWatcherFunctions: ( diff --git a/src/types/watchFolder/index.ts b/src/types/watchFolder/index.ts index fdd29e4d9cdd29ddf2c5a50579a3d3805ad2c954..8d9757b3695c2c27435df5d896fc3fa2bdd899c2 100644 --- a/src/types/watchFolder/index.ts +++ b/src/types/watchFolder/index.ts @@ -3,6 +3,7 @@ import { ElectronFile } from 'types/upload'; export interface WatchMapping { collectionName: string; folderPath: string; + hasMultipleFolders: boolean; files: { path: string; id: number; @@ -11,7 +12,8 @@ export interface WatchMapping { export interface EventQueueItem { type: 'upload' | 'trash'; - collectionName: string; + folderPath: string; + collectionName?: string; paths?: string[]; files?: ElectronFile[]; } From 504154065cb2511df30a000b14c93dfa316757b4 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Wed, 22 Jun 2022 11:27:50 +0530 Subject: [PATCH 062/295] added choice modal --- src/components/WatchFolder/index.tsx | 94 ++++++++++++++++++---------- 1 file changed, 61 insertions(+), 33 deletions(-) diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index 8bb2cd2345eaf158167c6d2f4de0ba83e70060b2..4c4e12fd1a0c593f8b413d66c2f1daf0fa612244 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -8,6 +8,7 @@ import { AppContext } from 'pages/_app'; import constants from 'utils/strings/constants'; import DialogBoxBase from 'components/DialogBox/base'; import DialogTitleWithCloseButton from 'components/DialogBox/titleWithCloseButton'; +import UploadStrategyChoiceModal from 'components/pages/gallery/UploadStrategyChoiceModal'; interface Iprops { open: boolean; @@ -16,6 +17,8 @@ interface Iprops { export default function WatchFolder({ open, onClose }: Iprops) { const [mappings, setMappings] = useState([]); + const [inputFolderPath, setInputFolderPath] = useState(''); + const [choicModalOpen, setChoiceModalOpen] = useState(false); const appContext = useContext(AppContext); useEffect(() => { @@ -36,7 +39,8 @@ export default function WatchFolder({ open, onClose }: Iprops) { const folder: any = folders[i]; const path = (folder.path as string).replace(/\\/g, '/'); if (await watchFolderService.isFolder(path)) { - await handleAddWatchMapping(path); + setInputFolderPath(path); + setChoiceModalOpen(true); } } }; @@ -47,16 +51,20 @@ export default function WatchFolder({ open, onClose }: Iprops) { const handleFolderSelection = async () => { const folderPath = await watchFolderService.selectFolder(); - await handleAddWatchMapping(folderPath); + if (folderPath?.length > 0) { + setInputFolderPath(folderPath); + setChoiceModalOpen(true); + } }; - const handleAddWatchMapping = async (inputFolderPath: string) => { + const handleAddWatchMapping = async (hasMultipleFolders: boolean) => { if (inputFolderPath?.length > 0) { await watchFolderService.addWatchMapping( inputFolderPath.substring(inputFolderPath.lastIndexOf('/') + 1), inputFolderPath, - true + hasMultipleFolders ); + setInputFolderPath(''); setMappings(watchFolderService.getWatchMappings()); } }; @@ -66,36 +74,56 @@ export default function WatchFolder({ open, onClose }: Iprops) { setMappings(watchFolderService.getWatchMappings()); }; + const onChoiceModalClose = () => setChoiceModalOpen(false); + + const uploadToSingleCollection = () => { + setChoiceModalOpen(false); + handleAddWatchMapping(false); + }; + + const uploadToMultipleCollection = () => { + setChoiceModalOpen(false); + handleAddWatchMapping(true); + }; + return ( - - - {constants.WATCHED_FOLDERS} - - - {mappings.length === 0 ? ( - - ) : ( - - )} - + <> + + + {constants.WATCHED_FOLDERS} + + + {mappings.length === 0 ? ( + + ) : ( + + )} + - - - - + + + + + + ); } From 767d1d26133d173bdac0027a0b5349334c0bca92 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Wed, 22 Jun 2022 11:29:14 +0530 Subject: [PATCH 063/295] fix path bug --- src/services/watchFolder/watchFolderService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/watchFolder/watchFolderService.ts b/src/services/watchFolder/watchFolderService.ts index 15407fa300bbacb4d39951a26cec9ae9649de93d..0e3709f40b38d5f87b11b6935513d2dab5aad8bf 100644 --- a/src/services/watchFolder/watchFolderService.ts +++ b/src/services/watchFolder/watchFolderService.ts @@ -443,7 +443,7 @@ class watchFolderService { const mappings = this.getWatchMappings(); const mapping = mappings.find((mapping) => - filePath.startsWith(mapping.folderPath + '/') + filePath.startsWith(mapping.folderPath) ); if (!mapping) { From e568261c6d6a9d9d282a75bc34fabb9a11060a6a Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Wed, 22 Jun 2022 11:44:45 +0530 Subject: [PATCH 064/295] fix live photo magic metadata --- src/services/upload/livePhotoService.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/services/upload/livePhotoService.ts b/src/services/upload/livePhotoService.ts index 7fbf44a2b06292e5e5336b38a673aa99cb816258..80b84e4f39bed5cf6ba7ee1a1eeb33c944a588cc 100644 --- a/src/services/upload/livePhotoService.ts +++ b/src/services/upload/livePhotoService.ts @@ -1,6 +1,7 @@ import { FILE_TYPE } from 'constants/file'; import { LIVE_PHOTO_ASSET_SIZE_LIMIT } from 'constants/upload'; import { encodeMotionPhoto } from 'services/motionPhotoService'; +import { NEW_FILE_MAGIC_METADATA } from 'types/magicMetadata'; import { ElectronFile, FileTypeInfo, @@ -192,6 +193,15 @@ export function clusterLivePhotoFiles(mediaFiles: FileWithCollection[]) { uploadService.setFileMetadataAndFileTypeInfo(livePhotoLocalID, { fileTypeInfo: { ...livePhotoFileTypeInfo }, metadata: { ...livePhotoMetadata }, + magicMetadata: { + ...NEW_FILE_MAGIC_METADATA, + data: { + filePaths: [ + (firstMediaFile.file as any).path as string, + (secondMediaFile.file as any).path as string, + ], + }, + }, }); index += 2; } else { From fa471202835d0bbea7bfb197478c0fd0044c964f Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Wed, 22 Jun 2022 14:09:40 +0530 Subject: [PATCH 065/295] remove unrequired prop --- src/pages/gallery/index.tsx | 9 +-------- src/types/gallery/index.ts | 1 - 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index e23cb7bb01b9d10c1cd5f18ae825cfd3ac593db1..cadedbbb944fbcb2413541203ea2135f4fae036f 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -127,7 +127,6 @@ const defaultGalleryContext: GalleryContextType = { syncWithRemote: () => null, setNotificationAttributes: () => null, setBlockingLoad: () => null, - setDropZoneActive: () => null, photoListHeader: null, }; @@ -158,7 +157,6 @@ export default function Gallery() { const [collectionNamerView, setCollectionNamerView] = useState(false); const [search, setSearch] = useState(null); const [uploadInProgress, setUploadInProgress] = useState(false); - const [dropZoneDisabled, setDropZoneDisabled] = useState(false); const { getRootProps, @@ -169,7 +167,7 @@ export default function Gallery() { } = useDropzone({ noClick: true, noKeyboard: true, - disabled: uploadInProgress || dropZoneDisabled, + disabled: uploadInProgress, }); const [isInSearchMode, setIsInSearchMode] = useState(false); @@ -589,10 +587,6 @@ export default function Gallery() { finishLoading(); }; - const setDropZoneActive = (active: boolean) => { - setDropZoneDisabled(!active); - }; - const openUploader = () => { if (importService.checkAllElectronAPIsExists()) { setUploadTypeSelectorView(true); @@ -615,7 +609,6 @@ export default function Gallery() { syncWithRemote, setNotificationAttributes, setBlockingLoad, - setDropZoneActive, photoListHeader: photoListHeader, }}> Promise; setNotificationAttributes: (attributes: NotificationAttributes) => void; setBlockingLoad: (value: boolean) => void; - setDropZoneActive: (value: boolean) => void; photoListHeader: TimeStampListItem; }; From 97d9621dc7954a7c7c91e9eeb5efe95508c1e212 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Thu, 23 Jun 2022 16:28:45 +0530 Subject: [PATCH 066/295] refactor watch service --- src/components/WatchFolder/index.tsx | 27 ++++++------ .../WatchFolder/mappingEntry/entryHeading.tsx | 2 +- src/components/WatchFolder/mappingList.tsx | 2 +- src/components/pages/gallery/Upload.tsx | 2 +- src/services/watchFolder/utils.ts | 5 +++ .../watchFolder/watchFolderEventHandlers.ts | 33 +++++++------- .../watchFolder/watchFolderService.ts | 44 +++++++++++-------- src/types/electron/index.ts | 2 +- src/types/watchFolder/index.ts | 5 ++- 9 files changed, 67 insertions(+), 55 deletions(-) create mode 100644 src/services/watchFolder/utils.ts diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index 4c4e12fd1a0c593f8b413d66c2f1daf0fa612244..0c9f90e6b9f594a40bb61a5010beae9468b68f68 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -9,6 +9,7 @@ import constants from 'utils/strings/constants'; import DialogBoxBase from 'components/DialogBox/base'; import DialogTitleWithCloseButton from 'components/DialogBox/titleWithCloseButton'; import UploadStrategyChoiceModal from 'components/pages/gallery/UploadStrategyChoiceModal'; +import { UPLOAD_STRATEGY } from 'components/pages/gallery/Upload'; interface Iprops { open: boolean; @@ -57,16 +58,14 @@ export default function WatchFolder({ open, onClose }: Iprops) { } }; - const handleAddWatchMapping = async (hasMultipleFolders: boolean) => { - if (inputFolderPath?.length > 0) { - await watchFolderService.addWatchMapping( - inputFolderPath.substring(inputFolderPath.lastIndexOf('/') + 1), - inputFolderPath, - hasMultipleFolders - ); - setInputFolderPath(''); - setMappings(watchFolderService.getWatchMappings()); - } + const handleAddWatchMapping = async (uploadStrategy: UPLOAD_STRATEGY) => { + await watchFolderService.addWatchMapping( + inputFolderPath.substring(inputFolderPath.lastIndexOf('/') + 1), + inputFolderPath, + uploadStrategy + ); + setInputFolderPath(''); + setMappings(watchFolderService.getWatchMappings()); }; const handleRemoveWatchMapping = async (mapping: WatchMapping) => { @@ -74,16 +73,16 @@ export default function WatchFolder({ open, onClose }: Iprops) { setMappings(watchFolderService.getWatchMappings()); }; - const onChoiceModalClose = () => setChoiceModalOpen(false); + const closeChoiceModal = () => setChoiceModalOpen(false); const uploadToSingleCollection = () => { setChoiceModalOpen(false); - handleAddWatchMapping(false); + handleAddWatchMapping(UPLOAD_STRATEGY.SINGLE_COLLECTION); }; const uploadToMultipleCollection = () => { setChoiceModalOpen(false); - handleAddWatchMapping(true); + handleAddWatchMapping(UPLOAD_STRATEGY.COLLECTION_PER_FOLDER); }; return ( @@ -120,7 +119,7 @@ export default function WatchFolder({ open, onClose }: Iprops) { diff --git a/src/components/WatchFolder/mappingEntry/entryHeading.tsx b/src/components/WatchFolder/mappingEntry/entryHeading.tsx index 0e2f6d42c082281e32db24cd91f628362249b61a..12553f63e29f23cb59f37532e501a3069edaaf89 100644 --- a/src/components/WatchFolder/mappingEntry/entryHeading.tsx +++ b/src/components/WatchFolder/mappingEntry/entryHeading.tsx @@ -19,7 +19,7 @@ export function EntryHeading({ mapping }: Iprops) { fontSize: '16px', lineHeight: '20px', }}> - {mapping.collectionName} + {mapping.rootFolderName} {appContext.isFolderSyncRunning && watchFolderService.isMappingSyncing(mapping) && ( diff --git a/src/components/WatchFolder/mappingList.tsx b/src/components/WatchFolder/mappingList.tsx index 1578ed7af90f1b4e9871e15a4b44f695a225f524..91633a31208554962400324c48fe97d3a6647554 100644 --- a/src/components/WatchFolder/mappingList.tsx +++ b/src/components/WatchFolder/mappingList.tsx @@ -13,7 +13,7 @@ export function MappingList({ mappings, handleRemoveWatchMapping }: Iprops) { {mappings.map((mapping) => { return ( diff --git a/src/components/pages/gallery/Upload.tsx b/src/components/pages/gallery/Upload.tsx index 4db1d7d8f4fb1dfc32d78b6cd952157de20502a0..86d9451a1eb539ebc132b48ccb9126fc4721237d 100644 --- a/src/components/pages/gallery/Upload.tsx +++ b/src/components/pages/gallery/Upload.tsx @@ -59,7 +59,7 @@ interface Props { showSessionExpiredMessage: () => void; } -enum UPLOAD_STRATEGY { +export enum UPLOAD_STRATEGY { SINGLE_COLLECTION, COLLECTION_PER_FOLDER, } diff --git a/src/services/watchFolder/utils.ts b/src/services/watchFolder/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..bce90a2c80dceaba5c6578f528af4cb73d6e0208 --- /dev/null +++ b/src/services/watchFolder/utils.ts @@ -0,0 +1,5 @@ +export const getParentFolderName = (filePath: string) => { + const folderPath = filePath.substring(0, filePath.lastIndexOf('/')); + const folderName = folderPath.substring(folderPath.lastIndexOf('/') + 1); + return folderName; +}; diff --git a/src/services/watchFolder/watchFolderEventHandlers.ts b/src/services/watchFolder/watchFolderEventHandlers.ts index a20c013163d567204875063fdd88427c787fdb0d..cf3c80dd1bfc7d600ab21a0f8469164119f51438 100644 --- a/src/services/watchFolder/watchFolderEventHandlers.ts +++ b/src/services/watchFolder/watchFolderEventHandlers.ts @@ -5,15 +5,15 @@ import watchFolderService from './watchFolderService'; export async function diskFileAddedCallback(file: ElectronFile) { try { - const { collectionName, folderPath } = - (await watchFolderService.getCollectionNameAndFolderPath( - file.path - )) ?? {}; + const collectionNameAndFolderPath = + await watchFolderService.getCollectionNameAndFolderPath(file.path); - if (!folderPath) { + if (!collectionNameAndFolderPath) { return; } + const { collectionName, folderPath } = collectionNameAndFolderPath; + console.log('added (upload) to event queue', collectionName, file); const event: EventQueueItem = { @@ -30,16 +30,17 @@ export async function diskFileAddedCallback(file: ElectronFile) { export async function diskFileRemovedCallback(filePath: string) { try { - const { collectionName, folderPath } = - (await watchFolderService.getCollectionNameAndFolderPath( - filePath - )) ?? {}; - console.log('added (trash) to event queue', collectionName, filePath); + const collectionNameAndFolderPath = + await watchFolderService.getCollectionNameAndFolderPath(filePath); - if (!folderPath) { + if (!collectionNameAndFolderPath) { return; } + const { collectionName, folderPath } = collectionNameAndFolderPath; + + console.log('added (trash) to event queue', collectionName, filePath); + const event: EventQueueItem = { type: 'trash', collectionName, @@ -54,14 +55,14 @@ export async function diskFileRemovedCallback(filePath: string) { export async function diskFolderRemovedCallback(folderPath: string) { try { - const { folderPath: mappedFolderPath } = - (await watchFolderService.getCollectionNameAndFolderPath( - folderPath - )) ?? {}; - if (!mappedFolderPath) { + const collectionNameAndFolderPath = + await watchFolderService.getCollectionNameAndFolderPath(folderPath); + if (!collectionNameAndFolderPath) { return; } + const { folderPath: mappedFolderPath } = collectionNameAndFolderPath; + if (mappedFolderPath === folderPath) { watchFolderService.pushTrashedDir(folderPath); } diff --git a/src/services/watchFolder/watchFolderService.ts b/src/services/watchFolder/watchFolderService.ts index 0e3709f40b38d5f87b11b6935513d2dab5aad8bf..20136264747d4bced70c5ea8a02dee5d0a20bcdb 100644 --- a/src/services/watchFolder/watchFolderService.ts +++ b/src/services/watchFolder/watchFolderService.ts @@ -16,6 +16,8 @@ import { diskFileRemovedCallback, diskFolderRemovedCallback, } from './watchFolderEventHandlers'; +import { UPLOAD_STRATEGY } from 'components/pages/gallery/Upload'; +import { getParentFolderName } from './utils'; class watchFolderService { private ElectronAPIs: ElectronAPIsInterface; @@ -101,9 +103,10 @@ class watchFolderService { for (const file of filesToUpload) { const event: EventQueueItem = { type: 'upload', - collectionName: mapping.hasMultipleFolders - ? this.getParentFolderName(file.path) - : mapping.collectionName, + collectionName: this.getCollectionNameForMapping( + mapping, + file.path + ), folderPath: mapping.folderPath, files: [file], }; @@ -126,9 +129,10 @@ class watchFolderService { for (const file of filesToRemove) { const event: EventQueueItem = { type: 'trash', - collectionName: mapping.hasMultipleFolders - ? this.getParentFolderName(file.path) - : mapping.collectionName, + collectionName: this.getCollectionNameForMapping( + mapping, + file.path + ), folderPath: mapping.folderPath, paths: [file.path], }; @@ -173,16 +177,16 @@ class watchFolderService { } async addWatchMapping( - collectionName: string, + rootFolderName: string, folderPath: string, - hasMultipleFolders: boolean + uploadStrategy: UPLOAD_STRATEGY ) { if (this.allElectronAPIsExist) { try { await this.ElectronAPIs.addWatchMapping( - collectionName, + rootFolderName, folderPath, - hasMultipleFolders + uploadStrategy === UPLOAD_STRATEGY.COLLECTION_PER_FOLDER ); } catch (e) { logError(e, 'error while adding watch mapping'); @@ -451,9 +455,10 @@ class watchFolderService { } return { - collectionName: mapping.hasMultipleFolders - ? this.getParentFolderName(filePath) - : mapping.collectionName, + collectionName: this.getCollectionNameForMapping( + mapping, + filePath + ), folderPath: mapping.folderPath, }; } catch (e) { @@ -461,12 +466,13 @@ class watchFolderService { } } - private getParentFolderName(filePath: string) { - const folderPath = filePath.substring(0, filePath.lastIndexOf('/')); - const folderName = folderPath.substring( - folderPath.lastIndexOf('/') + 1 - ); - return folderName; + private getCollectionNameForMapping( + mapping: WatchMapping, + filePath: string + ) { + return mapping.uploadStrategy === UPLOAD_STRATEGY.COLLECTION_PER_FOLDER + ? getParentFolderName(filePath) + : mapping.rootFolderName; } async selectFolder(): Promise { diff --git a/src/types/electron/index.ts b/src/types/electron/index.ts index 893b0174dbc1baa5ee82687badea8cde489cdcb2..653ea77f35bf177ee33a4ed11c07e91f31053c1f 100644 --- a/src/types/electron/index.ts +++ b/src/types/electron/index.ts @@ -43,7 +43,7 @@ export interface ElectronAPIsInterface { addWatchMapping: ( collectionName: string, folderPath: string, - hasMultipleFolders: boolean + uploadStrategy: boolean ) => Promise; removeWatchMapping: (folderPath: string) => Promise; registerWatcherFunctions: ( diff --git a/src/types/watchFolder/index.ts b/src/types/watchFolder/index.ts index 8d9757b3695c2c27435df5d896fc3fa2bdd899c2..1c02e4b44f5c54f0f962d7eb6e275e039929f56e 100644 --- a/src/types/watchFolder/index.ts +++ b/src/types/watchFolder/index.ts @@ -1,9 +1,10 @@ +import { UPLOAD_STRATEGY } from 'components/pages/gallery/Upload'; import { ElectronFile } from 'types/upload'; export interface WatchMapping { - collectionName: string; + rootFolderName: string; folderPath: string; - hasMultipleFolders: boolean; + uploadStrategy: UPLOAD_STRATEGY; files: { path: string; id: number; From 7f76945ddae3fc1607b7c648cc6c8a5bf58a2ba8 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 23 Jun 2022 16:50:52 +0530 Subject: [PATCH 067/295] change if else to switch case --- src/services/upload/uploadManager.ts | 58 ++++++++++++++-------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index f711dae86f8cf4676dacffa9ff0af621777adf14..f3643110b8ec3ce971fc159e8676e8513be8513d 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -357,36 +357,38 @@ class UploadManager { let decryptedFile: EnteFile; logUploadInfo(`uploadedFile ${JSON.stringify(uploadedFile)}`); this.updateElectronRemainingFiles(fileWithCollection); - if ( - fileUploadResult === - UPLOAD_RESULT.LARGER_THAN_AVAILABLE_STORAGE || - fileUploadResult === UPLOAD_RESULT.TOO_LARGE || - fileUploadResult === UPLOAD_RESULT.UNSUPPORTED - ) { - // no-op - } else if ( - fileUploadResult === UPLOAD_RESULT.FAILED || - fileUploadResult === UPLOAD_RESULT.BLOCKED - ) { - this.failedFiles.push(fileWithCollection); - } else if (fileUploadResult === UPLOAD_RESULT.ALREADY_UPLOADED) { - if (isElectron()) { - await watchFolderService.onFileUpload( - fileWithCollection, - uploadedFile + switch (fileUploadResult) { + case UPLOAD_RESULT.LARGER_THAN_AVAILABLE_STORAGE: + case UPLOAD_RESULT.TOO_LARGE: + case UPLOAD_RESULT.UNSUPPORTED: + // no-op + return; + case UPLOAD_RESULT.FAILED: + case UPLOAD_RESULT.BLOCKED: + this.failedFiles.push(fileWithCollection); + return; + case UPLOAD_RESULT.ALREADY_UPLOADED: { + if (isElectron()) { + await watchFolderService.onFileUpload( + fileWithCollection, + uploadedFile + ); + } + return; + } + case UPLOAD_RESULT.UPLOADED: + case UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL: { + decryptedFile = await decryptFile( + uploadedFile, + fileWithCollection.collection.key ); + break; } - } else if ( - fileUploadResult === UPLOAD_RESULT.UPLOADED || - fileUploadResult === - UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL - ) { - decryptedFile = await decryptFile( - uploadedFile, - fileWithCollection.collection.key - ); - } else { - decryptedFile = uploadedFile; + case UPLOAD_RESULT.ADDED_SYMLINK: + decryptedFile = uploadedFile; + break; + default: + throw Error('invalid result'); } await this.updateExistingFiles(decryptedFile); this.updateExistingCollections(decryptedFile); From 59295f849d1aebfa27cf8420488902c3a339bfa3 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 23 Jun 2022 16:59:10 +0530 Subject: [PATCH 068/295] reorder cases --- src/services/upload/uploadManager.ts | 34 +++++++++++++--------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index f3643110b8ec3ce971fc159e8676e8513be8513d..e7678930c83954d715864143ad032191a8c08acb 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -358,41 +358,39 @@ class UploadManager { logUploadInfo(`uploadedFile ${JSON.stringify(uploadedFile)}`); this.updateElectronRemainingFiles(fileWithCollection); switch (fileUploadResult) { - case UPLOAD_RESULT.LARGER_THAN_AVAILABLE_STORAGE: - case UPLOAD_RESULT.TOO_LARGE: - case UPLOAD_RESULT.UNSUPPORTED: - // no-op - return; case UPLOAD_RESULT.FAILED: case UPLOAD_RESULT.BLOCKED: this.failedFiles.push(fileWithCollection); - return; - case UPLOAD_RESULT.ALREADY_UPLOADED: { + break; + case UPLOAD_RESULT.ALREADY_UPLOADED: if (isElectron()) { await watchFolderService.onFileUpload( fileWithCollection, uploadedFile ); } - return; - } + break; + case UPLOAD_RESULT.ADDED_SYMLINK: + decryptedFile = uploadedFile; + break; case UPLOAD_RESULT.UPLOADED: - case UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL: { + case UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL: decryptedFile = await decryptFile( uploadedFile, fileWithCollection.collection.key ); break; - } - case UPLOAD_RESULT.ADDED_SYMLINK: - decryptedFile = uploadedFile; - break; default: - throw Error('invalid result'); + // no-op + } + if (decryptedFile) { + await this.updateExistingFiles(decryptedFile); + this.updateExistingCollections(decryptedFile); + await this.watchFolderCallback( + fileWithCollection, + uploadedFile + ); } - await this.updateExistingFiles(decryptedFile); - this.updateExistingCollections(decryptedFile); - await this.watchFolderCallback(fileWithCollection, uploadedFile); } catch (e) { logError(e, 'failed to do post file upload action'); logUploadInfo( From 0842abf8a3c16c866d39b8b99a40c55ece7cdfba Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Thu, 23 Jun 2022 19:10:19 +0530 Subject: [PATCH 069/295] refactor --- src/services/upload/livePhotoService.ts | 22 ++++++------ src/services/upload/uploadManager.ts | 18 ++++++---- src/services/upload/uploader.ts | 48 ++----------------------- src/types/upload/index.ts | 2 +- src/utils/file/index.ts | 33 +++++++++++++++++ src/utils/upload/index.ts | 18 +--------- 6 files changed, 61 insertions(+), 80 deletions(-) diff --git a/src/services/upload/livePhotoService.ts b/src/services/upload/livePhotoService.ts index 80b84e4f39bed5cf6ba7ee1a1eeb33c944a588cc..740c4da2a64c14c821578d35e51ae108ce800d74 100644 --- a/src/services/upload/livePhotoService.ts +++ b/src/services/upload/livePhotoService.ts @@ -1,7 +1,7 @@ import { FILE_TYPE } from 'constants/file'; import { LIVE_PHOTO_ASSET_SIZE_LIMIT } from 'constants/upload'; import { encodeMotionPhoto } from 'services/motionPhotoService'; -import { NEW_FILE_MAGIC_METADATA } from 'types/magicMetadata'; +import { FileMagicMetadata } from 'types/file'; import { ElectronFile, FileTypeInfo, @@ -62,6 +62,14 @@ export function getLivePhotoMetadata( }; } +export function getLivePhotoMagicMetadata( + imageFile: FileWithCollection +): FileMagicMetadata['data'] { + return { + filePaths: [getLivePhotoName((imageFile.file as any).path as string)], + }; +} + export function getLivePhotoSize(livePhotoAssets: LivePhotoAssets) { return livePhotoAssets.image.size + livePhotoAssets.video.size; } @@ -190,18 +198,12 @@ export function clusterLivePhotoFiles(mediaFiles: FileWithCollection[]) { imageAsset.metadata, videoAsset.metadata ); + const livePhotoMagicMetadata: FileMagicMetadata['data'] = + getLivePhotoMagicMetadata(firstMediaFile); uploadService.setFileMetadataAndFileTypeInfo(livePhotoLocalID, { fileTypeInfo: { ...livePhotoFileTypeInfo }, metadata: { ...livePhotoMetadata }, - magicMetadata: { - ...NEW_FILE_MAGIC_METADATA, - data: { - filePaths: [ - (firstMediaFile.file as any).path as string, - (secondMediaFile.file as any).path as string, - ], - }, - }, + magicMetadata: { ...livePhotoMagicMetadata }, }); index += 2; } else { diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index d546e09be698433ca659cad382d27a4f8c6b99b3..05dd0adb8941fb83ed469575de615b09f5640b65 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -6,6 +6,7 @@ import { sortFiles, preservePhotoswipeProps, decryptFile, + changeMagicMetadataFilePaths, } from 'utils/file'; import { logError } from 'utils/sentry'; import { getMetadataJSONMapKey, parseMetadataJSON } from './metadataService'; @@ -40,7 +41,6 @@ import isElectron from 'is-electron'; import ImportService from 'services/importService'; import watchFolderService from 'services/watchFolder/watchFolderService'; import { ProgressUpdater } from 'types/upload/ui'; -import { NEW_FILE_MAGIC_METADATA } from 'types/magicMetadata'; const MAX_CONCURRENT_UPLOADS = 4; const FILE_UPLOAD_COMPLETED = 100; @@ -261,11 +261,8 @@ class UploadManager { fileTypeInfo )) || null; const magicMetadata = { - ...NEW_FILE_MAGIC_METADATA, - data: { - filePaths: [(file as any).path as string], - }, - } as FileMagicMetadata; + filePaths: [(file as any).path as string], + } as FileMagicMetadata['data']; return { fileTypeInfo, metadata, magicMetadata }; })(); @@ -344,6 +341,15 @@ class UploadManager { this.existingFiles, fileWithCollection ); + const filePaths = UploadService.getFileMetadataAndFileTypeInfo( + fileWithCollection.localID + ).magicMetadata.filePaths; + await changeMagicMetadataFilePaths( + fileUploadResult, + uploadedFile, + fileWithCollection.collection.key, + filePaths + ); UIService.moveFileToResultList( fileWithCollection.localID, fileUploadResult diff --git a/src/services/upload/uploader.ts b/src/services/upload/uploader.ts index 91e69932574be97031abd28510eee89ff4858aa5..c62522630945f462b9c1c411daefd99adc4fb348 100644 --- a/src/services/upload/uploader.ts +++ b/src/services/upload/uploader.ts @@ -1,10 +1,9 @@ -import { EnteFile, FileMagicMetadata } from 'types/file'; +import { EnteFile } from 'types/file'; import { handleUploadError, CustomError } from 'utils/error'; import { logError } from 'utils/sentry'; import { findSameFileInCollection, findSameFileInOtherCollection, - getMergedMagicMetadataFilePaths, shouldDedupeAcrossCollection, } from 'utils/upload'; import UploadHttpClient from './uploadHttpClient'; @@ -17,10 +16,6 @@ import { logUploadInfo } from 'utils/upload'; import { convertBytesToHumanReadable } from 'utils/billing'; import { sleep } from 'utils/common'; import { addToCollection } from 'services/collectionService'; -import { updateMagicMetadataProps } from 'utils/magicMetadata'; -import { updateFileMagicMetadata } from 'services/fileService'; -import { NEW_FILE_MAGIC_METADATA } from 'types/magicMetadata'; -import { getFileKey } from 'utils/file'; interface UploadResponse { fileUploadResult: UPLOAD_RESULT; @@ -28,25 +23,6 @@ interface UploadResponse { skipDecryption?: boolean; } -const updateMagicMetadata = async ( - file: EnteFile, - magicMetadata: FileMagicMetadata, - collectionKey: string -) => { - magicMetadata.data.filePaths = getMergedMagicMetadataFilePaths( - file.magicMetadata, - magicMetadata - ); - file.key = await getFileKey(file, collectionKey); - const updatedMagicMetadata = await updateMagicMetadataProps( - file.magicMetadata ?? NEW_FILE_MAGIC_METADATA, - file.key, - { filePaths: magicMetadata.data.filePaths } - ); - file.magicMetadata = updatedMagicMetadata; - await updateFileMagicMetadata([file]); -}; - export default async function uploader( worker: any, existingFilesInCollection: EnteFile[], @@ -61,7 +37,7 @@ export default async function uploader( logUploadInfo(`uploader called for ${fileNameSize}`); UIService.setFileProgress(localID, 0); await sleep(0); - const { fileTypeInfo, metadata, magicMetadata } = + const { fileTypeInfo, metadata } = UploadService.getFileMetadataAndFileTypeInfo(localID); try { const fileSize = UploadService.getAssetSize(uploadAsset); @@ -81,11 +57,6 @@ export default async function uploader( ); if (sameFileInSameCollection) { logUploadInfo(`skipped upload for ${fileNameSize}`); - await updateMagicMetadata( - sameFileInSameCollection, - magicMetadata, - fileWithCollection.collection.key - ); return { fileUploadResult: UPLOAD_RESULT.ALREADY_UPLOADED, uploadedFile: sameFileInSameCollection, @@ -104,11 +75,6 @@ export default async function uploader( const resultFile = Object.assign({}, sameFileInOtherCollection); resultFile.collectionID = collection.id; await addToCollection(collection, [resultFile]); - await updateMagicMetadata( - resultFile, - magicMetadata, - fileWithCollection.collection.key - ); return { fileUploadResult: UPLOAD_RESULT.UPLOADED, uploadedFile: resultFile, @@ -126,11 +92,6 @@ export default async function uploader( metadata ); if (sameFileInOtherCollection) { - await updateMagicMetadata( - sameFileInOtherCollection, - magicMetadata, - fileWithCollection.collection.key - ); return { fileUploadResult: UPLOAD_RESULT.ALREADY_UPLOADED, uploadedFile: sameFileInOtherCollection, @@ -176,11 +137,6 @@ export default async function uploader( UIService.increaseFileUploaded(); logUploadInfo(`${fileNameSize} successfully uploaded`); - await updateMagicMetadata( - uploadedFile, - magicMetadata, - fileWithCollection.collection.key - ); return { fileUploadResult: metadata.hasStaticThumbnail ? UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL diff --git a/src/types/upload/index.ts b/src/types/upload/index.ts index 0f7716bef24f883734a43a87f1ed49874c76ed82..e473f419fa9fc3071f40f04d791292b2c0e12110 100644 --- a/src/types/upload/index.ts +++ b/src/types/upload/index.ts @@ -92,7 +92,7 @@ export interface FileWithCollection extends UploadAsset { export interface MetadataAndFileTypeInfo { metadata: Metadata; fileTypeInfo: FileTypeInfo; - magicMetadata: FileMagicMetadata; + magicMetadata: FileMagicMetadata['data']; } export type MetadataAndFileTypeInfoMap = Map; diff --git a/src/utils/file/index.ts b/src/utils/file/index.ts index 5a9e0f5e35756031ad191812cf40080f068eac5c..2fde13fe2bacb340fdc5af41f90eb47b258e48f6 100644 --- a/src/utils/file/index.ts +++ b/src/utils/file/index.ts @@ -26,6 +26,8 @@ import ffmpegService from 'services/ffmpeg/ffmpegService'; import { NEW_FILE_MAGIC_METADATA, VISIBILITY_STATE } from 'types/magicMetadata'; import { IsArchived, updateMagicMetadataProps } from 'utils/magicMetadata'; import { ARCHIVE_SECTION, TRASH_SECTION } from 'constants/collection'; +import { UPLOAD_RESULT } from 'constants/upload'; +import { updateFileMagicMetadata } from 'services/fileService'; export function downloadAsFile(filename: string, content: string) { const file = new Blob([content], { type: 'text/plain', @@ -452,6 +454,37 @@ export async function changeFileName(file: EnteFile, editedName: string) { return file; } +export const changeMagicMetadataFilePaths = async ( + fileUploadResult: UPLOAD_RESULT, + file: EnteFile, + collectionKey: string, + filePaths: string[] +) => { + if ( + fileUploadResult === UPLOAD_RESULT.UPLOADED || + fileUploadResult === UPLOAD_RESULT.ALREADY_UPLOADED || + fileUploadResult === UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL + ) { + let mergedMetadataFilePaths = [...filePaths]; + if (file.magicMetadata?.data.filePaths?.length > 0) { + mergedMetadataFilePaths = [ + ...new Set([ + ...file.magicMetadata.data.filePaths, + ...filePaths, + ]), + ]; + } + file.key = await getFileKey(file, collectionKey); + const updatedMagicMetadata = await updateMagicMetadataProps( + file.magicMetadata ?? NEW_FILE_MAGIC_METADATA, + file.key, + { filePaths: mergedMetadataFilePaths } + ); + file.magicMetadata = updatedMagicMetadata; + await updateFileMagicMetadata([file]); + } +}; + export function isSharedFile(file: EnteFile) { const user: User = getData(LS_KEYS.USER); diff --git a/src/utils/upload/index.ts b/src/utils/upload/index.ts index a002c29e6010b872afe7b6d68954fdeb38104bc8..71a27f47bcd62445a18cafc20d51502bf6cfe843 100644 --- a/src/utils/upload/index.ts +++ b/src/utils/upload/index.ts @@ -1,5 +1,5 @@ import { ElectronFile, FileWithCollection, Metadata } from 'types/upload'; -import { EnteFile, FileMagicMetadata } from 'types/file'; +import { EnteFile } from 'types/file'; import { convertBytesToHumanReadable } from 'utils/billing'; import { formatDateTime } from 'utils/file'; import { getLogs, saveLogLine } from 'utils/storage'; @@ -141,19 +141,3 @@ export function areFileWithCollectionsSame( ): boolean { return firstFile.localID === secondFile.localID; } - -export function getMergedMagicMetadataFilePaths( - oldMetadata: FileMagicMetadata, - newMetadata: FileMagicMetadata -): string[] { - if (!oldMetadata || !oldMetadata.data.filePaths) { - return newMetadata.data.filePaths; - } - const mergedMetadataFilePaths = [...oldMetadata.data.filePaths]; - newMetadata.data.filePaths.forEach((newMetadataFilePath) => { - if (!mergedMetadataFilePaths.includes(newMetadataFilePath)) { - mergedMetadataFilePaths.push(newMetadataFilePath); - } - }); - return mergedMetadataFilePaths; -} From d3242dbfa5ef330f7111f515f00c6784b555654b Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Thu, 23 Jun 2022 19:22:29 +0530 Subject: [PATCH 070/295] fix type --- src/services/watchFolder/watchFolderService.ts | 2 +- src/types/electron/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/watchFolder/watchFolderService.ts b/src/services/watchFolder/watchFolderService.ts index 20136264747d4bced70c5ea8a02dee5d0a20bcdb..61999ee6aea8e28dae5ce7ce386fda564255ad8e 100644 --- a/src/services/watchFolder/watchFolderService.ts +++ b/src/services/watchFolder/watchFolderService.ts @@ -186,7 +186,7 @@ class watchFolderService { await this.ElectronAPIs.addWatchMapping( rootFolderName, folderPath, - uploadStrategy === UPLOAD_STRATEGY.COLLECTION_PER_FOLDER + uploadStrategy ); } catch (e) { logError(e, 'error while adding watch mapping'); diff --git a/src/types/electron/index.ts b/src/types/electron/index.ts index 653ea77f35bf177ee33a4ed11c07e91f31053c1f..a239e3daa6a236db71c3a3e511a3d6dc76729e39 100644 --- a/src/types/electron/index.ts +++ b/src/types/electron/index.ts @@ -43,7 +43,7 @@ export interface ElectronAPIsInterface { addWatchMapping: ( collectionName: string, folderPath: string, - uploadStrategy: boolean + uploadStrategy: number ) => Promise; removeWatchMapping: (folderPath: string) => Promise; registerWatcherFunctions: ( From 087a35f6a35d071511547f7ba59371b01e532aad Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Thu, 23 Jun 2022 19:26:46 +0530 Subject: [PATCH 071/295] rename --- src/services/upload/uploadManager.ts | 4 ++-- src/utils/file/index.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index 05dd0adb8941fb83ed469575de615b09f5640b65..051a455e81b954e37627c2cf85b1c334170d2590 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -6,7 +6,7 @@ import { sortFiles, preservePhotoswipeProps, decryptFile, - changeMagicMetadataFilePaths, + changeFilePaths, } from 'utils/file'; import { logError } from 'utils/sentry'; import { getMetadataJSONMapKey, parseMetadataJSON } from './metadataService'; @@ -344,7 +344,7 @@ class UploadManager { const filePaths = UploadService.getFileMetadataAndFileTypeInfo( fileWithCollection.localID ).magicMetadata.filePaths; - await changeMagicMetadataFilePaths( + await changeFilePaths( fileUploadResult, uploadedFile, fileWithCollection.collection.key, diff --git a/src/utils/file/index.ts b/src/utils/file/index.ts index 2fde13fe2bacb340fdc5af41f90eb47b258e48f6..ceed4ba2fd5e6a59beac01ae46cdf35c489b6844 100644 --- a/src/utils/file/index.ts +++ b/src/utils/file/index.ts @@ -454,7 +454,7 @@ export async function changeFileName(file: EnteFile, editedName: string) { return file; } -export const changeMagicMetadataFilePaths = async ( +export const changeFilePaths = async ( fileUploadResult: UPLOAD_RESULT, file: EnteFile, collectionKey: string, From b0b54661c2a6188567b3c333f0034f2ca0141500 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Fri, 24 Jun 2022 11:11:21 +0530 Subject: [PATCH 072/295] move upload strategy to constants --- src/components/WatchFolder/index.tsx | 2 +- src/components/pages/gallery/Upload.tsx | 7 +------ src/constants/upload/index.ts | 5 +++++ src/services/watchFolder/watchFolderService.ts | 2 +- src/types/watchFolder/index.ts | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index 0c9f90e6b9f594a40bb61a5010beae9468b68f68..8bbed4a2516747ca6af15ca87c9510b9d520fdf5 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -9,7 +9,7 @@ import constants from 'utils/strings/constants'; import DialogBoxBase from 'components/DialogBox/base'; import DialogTitleWithCloseButton from 'components/DialogBox/titleWithCloseButton'; import UploadStrategyChoiceModal from 'components/pages/gallery/UploadStrategyChoiceModal'; -import { UPLOAD_STRATEGY } from 'components/pages/gallery/Upload'; +import { UPLOAD_STRATEGY } from 'constants/upload'; interface Iprops { open: boolean; diff --git a/src/components/pages/gallery/Upload.tsx b/src/components/pages/gallery/Upload.tsx index 86d9451a1eb539ebc132b48ccb9126fc4721237d..5e57c1806fbebc139125a89e525edca68d679486 100644 --- a/src/components/pages/gallery/Upload.tsx +++ b/src/components/pages/gallery/Upload.tsx @@ -33,7 +33,7 @@ import { SegregatedFinishedUploads, InProgressUpload, } from 'types/upload/ui'; -import { UPLOAD_STAGES } from 'constants/upload'; +import { UPLOAD_STAGES, UPLOAD_STRATEGY } from 'constants/upload'; const FIRST_ALBUM_NAME = 'My First Album'; @@ -59,11 +59,6 @@ interface Props { showSessionExpiredMessage: () => void; } -export enum UPLOAD_STRATEGY { - SINGLE_COLLECTION, - COLLECTION_PER_FOLDER, -} - export enum DESKTOP_UPLOAD_TYPE { FILES = 'files', FOLDERS = 'folders', diff --git a/src/constants/upload/index.ts b/src/constants/upload/index.ts index 2c9d7a4e6b3fe4ec5ba89c2fcaa5b681b9fde0ce..70912268253ff8caa48287b2e721e8bd567a22d6 100644 --- a/src/constants/upload/index.ts +++ b/src/constants/upload/index.ts @@ -31,6 +31,11 @@ export enum UPLOAD_STAGES { FINISH, } +export enum UPLOAD_STRATEGY { + SINGLE_COLLECTION, + COLLECTION_PER_FOLDER, +} + export enum UPLOAD_RESULT { FAILED, ALREADY_UPLOADED, diff --git a/src/services/watchFolder/watchFolderService.ts b/src/services/watchFolder/watchFolderService.ts index 61999ee6aea8e28dae5ce7ce386fda564255ad8e..717b6daf2ea643fd8aba0191fe7d07e070387101 100644 --- a/src/services/watchFolder/watchFolderService.ts +++ b/src/services/watchFolder/watchFolderService.ts @@ -16,8 +16,8 @@ import { diskFileRemovedCallback, diskFolderRemovedCallback, } from './watchFolderEventHandlers'; -import { UPLOAD_STRATEGY } from 'components/pages/gallery/Upload'; import { getParentFolderName } from './utils'; +import { UPLOAD_STRATEGY } from 'constants/upload'; class watchFolderService { private ElectronAPIs: ElectronAPIsInterface; diff --git a/src/types/watchFolder/index.ts b/src/types/watchFolder/index.ts index 1c02e4b44f5c54f0f962d7eb6e275e039929f56e..97fa96dceed2fb051ef2ba20b02264f9bb1a5f2b 100644 --- a/src/types/watchFolder/index.ts +++ b/src/types/watchFolder/index.ts @@ -1,4 +1,4 @@ -import { UPLOAD_STRATEGY } from 'components/pages/gallery/Upload'; +import { UPLOAD_STRATEGY } from 'constants/upload'; import { ElectronFile } from 'types/upload'; export interface WatchMapping { From ff04c9c89c72cf91a63e6c25e4c5926b02a02dce Mon Sep 17 00:00:00 2001 From: Abhinav Date: Fri, 24 Jun 2022 11:30:15 +0530 Subject: [PATCH 073/295] simply filePaths handling --- src/services/upload/livePhotoService.ts | 14 ++++---------- src/services/upload/uploadManager.ts | 23 +++++++++++------------ src/types/upload/index.ts | 4 ++-- src/utils/file/index.ts | 8 ++++---- 4 files changed, 21 insertions(+), 28 deletions(-) diff --git a/src/services/upload/livePhotoService.ts b/src/services/upload/livePhotoService.ts index 740c4da2a64c14c821578d35e51ae108ce800d74..1b2000cc1bc03452f80cad9e453080dc53c07978 100644 --- a/src/services/upload/livePhotoService.ts +++ b/src/services/upload/livePhotoService.ts @@ -1,7 +1,6 @@ import { FILE_TYPE } from 'constants/file'; import { LIVE_PHOTO_ASSET_SIZE_LIMIT } from 'constants/upload'; import { encodeMotionPhoto } from 'services/motionPhotoService'; -import { FileMagicMetadata } from 'types/file'; import { ElectronFile, FileTypeInfo, @@ -62,12 +61,8 @@ export function getLivePhotoMetadata( }; } -export function getLivePhotoMagicMetadata( - imageFile: FileWithCollection -): FileMagicMetadata['data'] { - return { - filePaths: [getLivePhotoName((imageFile.file as any).path as string)], - }; +export function getLivePhotoFilePath(imageAsset: Asset): string { + return getLivePhotoName((imageAsset.file as any).path); } export function getLivePhotoSize(livePhotoAssets: LivePhotoAssets) { @@ -198,12 +193,11 @@ export function clusterLivePhotoFiles(mediaFiles: FileWithCollection[]) { imageAsset.metadata, videoAsset.metadata ); - const livePhotoMagicMetadata: FileMagicMetadata['data'] = - getLivePhotoMagicMetadata(firstMediaFile); + const livePhotoPath = getLivePhotoFilePath(imageAsset); uploadService.setFileMetadataAndFileTypeInfo(livePhotoLocalID, { fileTypeInfo: { ...livePhotoFileTypeInfo }, metadata: { ...livePhotoMetadata }, - magicMetadata: { ...livePhotoMagicMetadata }, + filePath: livePhotoPath, }); index += 2; } else { diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index 051a455e81b954e37627c2cf85b1c334170d2590..cd548d88520324330fcd50fdb8da52630ca369b9 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -6,7 +6,7 @@ import { sortFiles, preservePhotoswipeProps, decryptFile, - changeFilePaths, + appendFilePath, } from 'utils/file'; import { logError } from 'utils/sentry'; import { getMetadataJSONMapKey, parseMetadataJSON } from './metadataService'; @@ -20,7 +20,7 @@ import UIService from './uiService'; import UploadService from './uploadService'; import { CustomError } from 'utils/error'; import { Collection } from 'types/collection'; -import { EnteFile, FileMagicMetadata } from 'types/file'; +import { EnteFile } from 'types/file'; import { FileWithCollection, MetadataAndFileTypeInfo, @@ -230,7 +230,7 @@ class UploadManager { UIService.reset(mediaFiles.length); for (const { file, localID, collectionID } of mediaFiles) { try { - const { fileTypeInfo, metadata, magicMetadata } = + const { fileTypeInfo, metadata, filePath } = await (async () => { if (file.size >= MAX_FILE_SIZE_SUPPORTED) { logUploadInfo( @@ -260,10 +260,8 @@ class UploadManager { collectionID, fileTypeInfo )) || null; - const magicMetadata = { - filePaths: [(file as any).path as string], - } as FileMagicMetadata['data']; - return { fileTypeInfo, metadata, magicMetadata }; + const filePath = (file as any).path as string; + return { fileTypeInfo, metadata, filePath }; })(); logUploadInfo( @@ -274,7 +272,7 @@ class UploadManager { this.metadataAndFileTypeInfoMap.set(localID, { fileTypeInfo: fileTypeInfo && { ...fileTypeInfo }, metadata: metadata && { ...metadata }, - magicMetadata: magicMetadata && { ...magicMetadata }, + filePath: filePath, }); UIService.increaseFileUploaded(); } catch (e) { @@ -341,14 +339,15 @@ class UploadManager { this.existingFiles, fileWithCollection ); - const filePaths = UploadService.getFileMetadataAndFileTypeInfo( + const filePath = UploadService.getFileMetadataAndFileTypeInfo( fileWithCollection.localID - ).magicMetadata.filePaths; - await changeFilePaths( + ).filePath; + + await appendFilePath( fileUploadResult, uploadedFile, fileWithCollection.collection.key, - filePaths + filePath ); UIService.moveFileToResultList( fileWithCollection.localID, diff --git a/src/types/upload/index.ts b/src/types/upload/index.ts index e473f419fa9fc3071f40f04d791292b2c0e12110..f42d5ead6b54da0d3f08622e94cda921df44b21d 100644 --- a/src/types/upload/index.ts +++ b/src/types/upload/index.ts @@ -1,6 +1,6 @@ import { FILE_TYPE } from 'constants/file'; import { Collection } from 'types/collection'; -import { fileAttribute, FileMagicMetadata } from 'types/file'; +import { fileAttribute } from 'types/file'; export interface DataStream { stream: ReadableStream; @@ -92,7 +92,7 @@ export interface FileWithCollection extends UploadAsset { export interface MetadataAndFileTypeInfo { metadata: Metadata; fileTypeInfo: FileTypeInfo; - magicMetadata: FileMagicMetadata['data']; + filePath: string; } export type MetadataAndFileTypeInfoMap = Map; diff --git a/src/utils/file/index.ts b/src/utils/file/index.ts index ceed4ba2fd5e6a59beac01ae46cdf35c489b6844..c768f683144bcebd7da8aee16d3bed7a784808af 100644 --- a/src/utils/file/index.ts +++ b/src/utils/file/index.ts @@ -454,23 +454,23 @@ export async function changeFileName(file: EnteFile, editedName: string) { return file; } -export const changeFilePaths = async ( +export const appendFilePath = async ( fileUploadResult: UPLOAD_RESULT, file: EnteFile, collectionKey: string, - filePaths: string[] + filePath: string ) => { if ( fileUploadResult === UPLOAD_RESULT.UPLOADED || fileUploadResult === UPLOAD_RESULT.ALREADY_UPLOADED || fileUploadResult === UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL ) { - let mergedMetadataFilePaths = [...filePaths]; + let mergedMetadataFilePaths = [filePath]; if (file.magicMetadata?.data.filePaths?.length > 0) { mergedMetadataFilePaths = [ ...new Set([ ...file.magicMetadata.data.filePaths, - ...filePaths, + ...mergedMetadataFilePaths, ]), ]; } From e022f5ef891f14825e0bfbe44c0d5384789351d5 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Fri, 24 Jun 2022 11:43:34 +0530 Subject: [PATCH 074/295] move file path upadting logic to post Upload action --- src/services/upload/uploadManager.ts | 33 +++++++++++--------- src/utils/file/index.ts | 45 ++++++++++------------------ 2 files changed, 35 insertions(+), 43 deletions(-) diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index 0781bc3d9152dca364afaa25d286fe67e6e12e31..2dd948c1b89f6d58947d31082b8e648dd2dad8b3 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -6,7 +6,7 @@ import { sortFiles, preservePhotoswipeProps, decryptFile, - appendFilePath, + appendNewFilePath, } from 'utils/file'; import { logError } from 'utils/sentry'; import { getMetadataJSONMapKey, parseMetadataJSON } from './metadataService'; @@ -338,26 +338,18 @@ class UploadManager { this.existingFiles, fileWithCollection ); - const filePath = UploadService.getFileMetadataAndFileTypeInfo( - fileWithCollection.localID - ).filePath; - await appendFilePath( + const finalUploadResult = await this.postUploadTask( fileUploadResult, uploadedFile, - fileWithCollection.collection.key, - filePath + fileWithCollection ); + UIService.moveFileToResultList( fileWithCollection.localID, - fileUploadResult + finalUploadResult ); UploadService.reducePendingUploadCount(); - await this.postUploadTask( - fileUploadResult, - uploadedFile, - fileWithCollection - ); } } @@ -403,14 +395,16 @@ class UploadManager { fileWithCollection, uploadedFile ); + await this.updateFilePaths(decryptedFile, fileWithCollection); } + return fileUploadResult; } catch (e) { logError(e, 'failed to do post file upload action'); logUploadInfo( `failed to do post file upload action -> ${e.message} ${(e as Error).stack}` ); - throw e; + return UPLOAD_RESULT.FAILED; } } @@ -456,6 +450,17 @@ class UploadManager { } } + private async updateFilePaths( + decryptedFile: EnteFile, + fileWithCollection: FileWithCollection + ) { + const filePath = UploadService.getFileMetadataAndFileTypeInfo( + fileWithCollection.localID + ).filePath; + + await appendNewFilePath(decryptedFile, filePath); + } + async retryFailedFiles() { await this.queueFilesForUpload(this.failedFiles, [ ...this.collections.values(), diff --git a/src/utils/file/index.ts b/src/utils/file/index.ts index c768f683144bcebd7da8aee16d3bed7a784808af..49f1c958902dd718b33f3cb3ca964e7fe814c7b7 100644 --- a/src/utils/file/index.ts +++ b/src/utils/file/index.ts @@ -26,7 +26,6 @@ import ffmpegService from 'services/ffmpeg/ffmpegService'; import { NEW_FILE_MAGIC_METADATA, VISIBILITY_STATE } from 'types/magicMetadata'; import { IsArchived, updateMagicMetadataProps } from 'utils/magicMetadata'; import { ARCHIVE_SECTION, TRASH_SECTION } from 'constants/collection'; -import { UPLOAD_RESULT } from 'constants/upload'; import { updateFileMagicMetadata } from 'services/fileService'; export function downloadAsFile(filename: string, content: string) { const file = new Blob([content], { @@ -454,35 +453,23 @@ export async function changeFileName(file: EnteFile, editedName: string) { return file; } -export const appendFilePath = async ( - fileUploadResult: UPLOAD_RESULT, - file: EnteFile, - collectionKey: string, - filePath: string -) => { - if ( - fileUploadResult === UPLOAD_RESULT.UPLOADED || - fileUploadResult === UPLOAD_RESULT.ALREADY_UPLOADED || - fileUploadResult === UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL - ) { - let mergedMetadataFilePaths = [filePath]; - if (file.magicMetadata?.data.filePaths?.length > 0) { - mergedMetadataFilePaths = [ - ...new Set([ - ...file.magicMetadata.data.filePaths, - ...mergedMetadataFilePaths, - ]), - ]; - } - file.key = await getFileKey(file, collectionKey); - const updatedMagicMetadata = await updateMagicMetadataProps( - file.magicMetadata ?? NEW_FILE_MAGIC_METADATA, - file.key, - { filePaths: mergedMetadataFilePaths } - ); - file.magicMetadata = updatedMagicMetadata; - await updateFileMagicMetadata([file]); +export const appendNewFilePath = async (file: EnteFile, filePath: string) => { + let mergedMetadataFilePaths = [filePath]; + if (file.magicMetadata?.data.filePaths?.length > 0) { + mergedMetadataFilePaths = [ + ...new Set([ + ...file.magicMetadata.data.filePaths, + ...mergedMetadataFilePaths, + ]), + ]; } + const updatedMagicMetadata = await updateMagicMetadataProps( + file.magicMetadata ?? NEW_FILE_MAGIC_METADATA, + file.key, + { filePaths: mergedMetadataFilePaths } + ); + file.magicMetadata = updatedMagicMetadata; + await updateFileMagicMetadata([file]); }; export function isSharedFile(file: EnteFile) { From 7b584774cdef78337a889caae126c7c31239db8c Mon Sep 17 00:00:00 2001 From: Abhinav Date: Fri, 24 Jun 2022 11:45:32 +0530 Subject: [PATCH 075/295] move api call to update path to uploadManager --- src/services/upload/uploadManager.ts | 9 +++++++-- src/utils/file/index.ts | 5 +++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index 2dd948c1b89f6d58947d31082b8e648dd2dad8b3..709237c2fed7181045231f82ecff455ad15c5362 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -1,4 +1,8 @@ -import { getLocalFiles, setLocalFiles } from '../fileService'; +import { + getLocalFiles, + setLocalFiles, + updateFileMagicMetadata, +} from '../fileService'; import { SetFiles } from 'types/gallery'; import { getDedicatedCryptoWorker } from 'utils/crypto'; import { @@ -458,7 +462,8 @@ class UploadManager { fileWithCollection.localID ).filePath; - await appendNewFilePath(decryptedFile, filePath); + const updatedFile = await appendNewFilePath(decryptedFile, filePath); + await updateFileMagicMetadata([updatedFile]); } async retryFailedFiles() { diff --git a/src/utils/file/index.ts b/src/utils/file/index.ts index 49f1c958902dd718b33f3cb3ca964e7fe814c7b7..c009d1ab9bf888e91a63f937b034b186258d817d 100644 --- a/src/utils/file/index.ts +++ b/src/utils/file/index.ts @@ -26,7 +26,7 @@ import ffmpegService from 'services/ffmpeg/ffmpegService'; import { NEW_FILE_MAGIC_METADATA, VISIBILITY_STATE } from 'types/magicMetadata'; import { IsArchived, updateMagicMetadataProps } from 'utils/magicMetadata'; import { ARCHIVE_SECTION, TRASH_SECTION } from 'constants/collection'; -import { updateFileMagicMetadata } from 'services/fileService'; + export function downloadAsFile(filename: string, content: string) { const file = new Blob([content], { type: 'text/plain', @@ -469,7 +469,8 @@ export const appendNewFilePath = async (file: EnteFile, filePath: string) => { { filePaths: mergedMetadataFilePaths } ); file.magicMetadata = updatedMagicMetadata; - await updateFileMagicMetadata([file]); + + return file; }; export function isSharedFile(file: EnteFile) { From 0a1076c584d0f04c317bcf2df8c7035fee455911 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Fri, 24 Jun 2022 12:27:01 +0530 Subject: [PATCH 076/295] fix update file paths when already uploaded --- src/services/upload/uploadManager.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index 709237c2fed7181045231f82ecff455ad15c5362..276410dc5e0bd1314fc6253b8e9b18452119568c 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -378,6 +378,10 @@ class UploadManager { uploadedFile ); } + await this.updateFilePaths( + uploadedFile, + fileWithCollection + ); break; case UPLOAD_RESULT.ADDED_SYMLINK: decryptedFile = uploadedFile; From 93a80ec38894b76d7cf608a38e8d77351f2e4946 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Sat, 23 Jul 2022 22:38:39 +0530 Subject: [PATCH 077/295] fix build --- src/components/Sidebar/UtilitySection.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Sidebar/UtilitySection.tsx b/src/components/Sidebar/UtilitySection.tsx index b544d3117a542d1df2389b61deb898783b44b21a..599fada0cc0c3ee555976eecb519741a2e2e90c3 100644 --- a/src/components/Sidebar/UtilitySection.tsx +++ b/src/components/Sidebar/UtilitySection.tsx @@ -36,7 +36,7 @@ export default function UtilitySection({ closeSidebar }) { } else { setDialogMessage({ title: constants.DOWNLOAD_APP, - content: constants.DOWNLOAD_APP_MESSAGE(), + content: constants.DOWNLOAD_APP_MESSAGE, proceed: { text: constants.DOWNLOAD, From 82f2652519c29d5803bdd576f1485a00db04373f Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Sun, 24 Jul 2022 00:06:42 +0530 Subject: [PATCH 078/295] fix build --- src/components/WatchFolder/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index 8bbed4a2516747ca6af15ca87c9510b9d520fdf5..2f6825975aa213a8ca525e278db948190033a38d 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -7,8 +7,8 @@ import { WatchMapping } from 'types/watchFolder'; import { AppContext } from 'pages/_app'; import constants from 'utils/strings/constants'; import DialogBoxBase from 'components/DialogBox/base'; -import DialogTitleWithCloseButton from 'components/DialogBox/titleWithCloseButton'; -import UploadStrategyChoiceModal from 'components/pages/gallery/UploadStrategyChoiceModal'; +import DialogTitleWithCloseButton from 'components/DialogBox/TitleWithCloseButton'; +import UploadStrategyChoiceModal from 'components/Upload/UploadStrategyChoiceModal'; import { UPLOAD_STRATEGY } from 'constants/upload'; interface Iprops { From 8f9e434a5a06a341d5fd436eeccc60084d98182f Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Tue, 26 Jul 2022 19:51:16 +0530 Subject: [PATCH 079/295] handle user upload when watch service is running --- src/components/Upload/Uploader.tsx | 88 +++++++++++++------ src/services/upload/uploadManager.ts | 21 +++++ .../watchFolder/watchFolderService.ts | 66 ++++++++++---- src/types/watchFolder/index.ts | 5 ++ src/utils/common/index.ts | 14 +++ 5 files changed, 148 insertions(+), 46 deletions(-) diff --git a/src/components/Upload/Uploader.tsx b/src/components/Upload/Uploader.tsx index 5cc76f8c9399a0a313b08f2dda1beb53783adb1e..8bfcdb6ed3c239a51311f9529dc3dbe09fe0fd0d 100644 --- a/src/components/Upload/Uploader.tsx +++ b/src/components/Upload/Uploader.tsx @@ -35,6 +35,7 @@ import { UPLOAD_STAGES } from 'constants/upload'; import importService from 'services/importService'; import { getDownloadAppMessage } from 'utils/ui'; import UploadTypeSelector from './UploadTypeSelector'; +import { newLock } from 'utils/common'; const FIRST_ALBUM_NAME = 'My First Album'; @@ -114,6 +115,8 @@ export default function Uploader(props: Props) { const pendingDesktopUploadCollectionName = useRef(''); const uploadType = useRef(null); const zipPaths = useRef(null); + const waitForPrevUpload = useRef>(null); + const uploadDone = useRef<() => void>(null); useEffect(() => { UploadManager.initUploader( @@ -156,8 +159,14 @@ export default function Uploader(props: Props) { appContext.sharedFiles?.length > 0 ) { if (props.uploadInProgress) { - // no-op - // a upload is already in progress + if (watchFolderService.isUploadRunning()) { + // pause watch folder service on user upload + uploadManager.pauseWatchService(); + } else { + // no-op + // a user upload is already in progress + return; + } } else if (isCanvasBlocked()) { appContext.setDialogMessage({ title: constants.CANVAS_BLOCKED_TITLE, @@ -170,29 +179,29 @@ export default function Uploader(props: Props) { variant: 'accent', }, }); - } else { - props.setLoading(true); - if (props.webFiles?.length > 0) { - // File selection by drag and drop or selection of file. - toUploadFiles.current = props.webFiles; - props.setWebFiles([]); - } else if (appContext.sharedFiles?.length > 0) { - toUploadFiles.current = appContext.sharedFiles; - appContext.resetSharedFiles(); - } else if (props.electronFiles?.length > 0) { - // File selection from desktop app - toUploadFiles.current = props.electronFiles; - props.setElectronFiles([]); - } - const analysisResult = analyseUploadFiles(); - setAnalysisResult(analysisResult); - - handleCollectionCreationAndUpload( - analysisResult, - props.isFirstUpload - ); - props.setLoading(false); + return; + } + props.setLoading(true); + if (props.webFiles?.length > 0) { + // File selection by drag and drop or selection of file. + toUploadFiles.current = props.webFiles; + props.setWebFiles([]); + } else if (appContext.sharedFiles?.length > 0) { + toUploadFiles.current = appContext.sharedFiles; + appContext.resetSharedFiles(); + } else if (props.electronFiles?.length > 0) { + // File selection from desktop app + toUploadFiles.current = props.electronFiles; + props.setElectronFiles([]); } + const analysisResult = analyseUploadFiles(); + setAnalysisResult(analysisResult); + + handleCollectionCreationAndUpload( + analysisResult, + props.isFirstUpload + ); + props.setLoading(false); } }, [props.webFiles, appContext.sharedFiles, props.electronFiles]); @@ -351,6 +360,10 @@ export default function Uploader(props: Props) { collections: Collection[] ) => { try { + if (waitForPrevUpload.current !== null) { + await waitForPrevUpload.current; // wait for previous upload to finish + } + setUploadLock(); uploadInit(); props.setUploadInProgress(true); props.closeCollectionSelector(); @@ -380,17 +393,36 @@ export default function Uploader(props: Props) { setUploadProgressView(false); throw err; } finally { + unsetUploadLock(); props.setUploadInProgress(false); props.syncWithRemote(); if (isElectron()) { - await watchFolderService.allFileUploadsDone( - filesWithCollectionToUpload, - collections - ); + if (watchFolderService.isUploadRunning()) { + await watchFolderService.allFileUploadsDone( + filesWithCollectionToUpload, + collections + ); + } else { + if (watchFolderService.isServicePaused()) { + // resume the service after user upload is done + watchFolderService.resumeService(); + } + } } } }; + const setUploadLock = () => { + const { wait, unlock } = newLock(); + waitForPrevUpload.current = wait; + uploadDone.current = unlock; + }; + + const unsetUploadLock = () => { + uploadDone.current(); + waitForPrevUpload.current = null; + }; + const retryFailed = async () => { try { props.setUploadInProgress(true); diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index 2c49a313a43caeb81d95da03d7053e7a02548f0a..fb2dee28e0322550f2a7cd3ae416568c4c34b475 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -61,6 +61,7 @@ class UploadManager { private existingFiles: EnteFile[]; private setFiles: SetFiles; private collections: Map; + private isUploadPausing: boolean = false; public initUploader(progressUpdater: ProgressUpdater, setFiles: SetFiles) { UIService.init(progressUpdater); this.setFiles = setFiles; @@ -179,6 +180,9 @@ class UploadManager { ); throw e; } finally { + if (this.isUploadPausing) { + this.isUploadPausing = false; + } for (let i = 0; i < MAX_CONCURRENT_UPLOADS; i++) { this.cryptoWorkers[i]?.worker.terminate(); } @@ -193,6 +197,10 @@ class UploadManager { for (const { file, collectionID } of metadataFiles) { try { + if (this.isUploadPausing) { + return; + } + logUploadInfo( `parsing metadata json file ${getFileNameSize(file)}` ); @@ -234,6 +242,9 @@ class UploadManager { logUploadInfo(`extractMetadataFromFiles executed`); UIService.reset(mediaFiles.length); for (const { file, localID, collectionID } of mediaFiles) { + if (this.isUploadPausing) { + return; + } try { const { fileTypeInfo, metadata, filePath } = await (async () => { @@ -361,6 +372,9 @@ class UploadManager { private async uploadNextFileInQueue(worker: any) { while (this.filesToBeUploaded.length > 0) { + if (this.isUploadPausing) { + return; + } let fileWithCollection = this.filesToBeUploaded.pop(); const { collectionID } = fileWithCollection; const existingFilesInCollection = @@ -459,6 +473,13 @@ class UploadManager { } } + public pauseWatchService() { + if (isElectron()) { + watchFolderService.pauseService(); + this.isUploadPausing = true; + } + } + private updateExistingCollections(decryptedFile: EnteFile) { if (!this.existingFilesCollectionWise.has(decryptedFile.collectionID)) { this.existingFilesCollectionWise.set( diff --git a/src/services/watchFolder/watchFolderService.ts b/src/services/watchFolder/watchFolderService.ts index 717b6daf2ea643fd8aba0191fe7d07e070387101..030f322eaee669564ba7533e8acf1fa23cbfcec2 100644 --- a/src/services/watchFolder/watchFolderService.ts +++ b/src/services/watchFolder/watchFolderService.ts @@ -28,6 +28,7 @@ class watchFolderService { private isEventRunning: boolean = false; private uploadRunning: boolean = false; private pathToIDMap = new Map(); + private isPaused = false; private setElectronFiles: (files: ElectronFile[]) => void; private setCollectionName: (collectionName: string) => void; private syncWithRemote: () => void; @@ -43,6 +44,10 @@ class watchFolderService { return this.uploadRunning; } + isServicePaused() { + return this.isPaused; + } + async init( setElectronFiles: (files: ElectronFile[]) => void, setCollectionName: (collectionName: string) => void, @@ -57,31 +62,43 @@ class watchFolderService { this.setWatchFolderServiceIsRunning = setWatchFolderServiceIsRunning; - let mappings = this.getWatchMappings(); + await this.getAndSyncDiffOfFiles(true); + } catch (e) { + logError(e, 'error while initializing watch service'); + } + } + } - console.log('mappings', mappings); + async getAndSyncDiffOfFiles(init = false) { + try { + let mappings = this.getWatchMappings(); - if (!mappings) { - return; - } + console.log('mappings', mappings); - mappings = await this.filterOutDeletedMappings(mappings); + if (!mappings) { + return; + } - for (const mapping of mappings) { - const filesOnDisk: ElectronFile[] = - await this.ElectronAPIs.getAllFilesFromDir( - mapping.folderPath - ); + mappings = await this.filterOutDeletedMappings(mappings); - this.uploadDiffOfFiles(mapping, filesOnDisk); - this.trashDiffOfFiles(mapping, filesOnDisk); - } + this.eventQueue = []; + for (const mapping of mappings) { + const filesOnDisk: ElectronFile[] = + await this.ElectronAPIs.getAllFilesFromDir( + mapping.folderPath + ); + + this.uploadDiffOfFiles(mapping, filesOnDisk); + this.trashDiffOfFiles(mapping, filesOnDisk); + } + + if (init) { this.setWatchFunctions(); - await this.runNextEvent(); - } catch (e) { - logError(e, 'error while initializing watch service'); } + await this.runNextEvent(); + } catch (e) { + logError(e, 'error while getting and syncing diff of files'); } } @@ -224,7 +241,11 @@ class watchFolderService { private async runNextEvent() { console.log('mappings', this.getWatchMappings()); - if (this.eventQueue.length === 0 || this.isEventRunning) { + if ( + this.eventQueue.length === 0 || + this.isEventRunning || + this.isPaused + ) { return; } @@ -513,6 +534,15 @@ class watchFolderService { logError(e, 'error while checking if folder exists'); } } + + pauseService() { + this.isPaused = true; + } + + resumeService() { + this.isPaused = false; + this.getAndSyncDiffOfFiles(); + } } export default new watchFolderService(); diff --git a/src/types/watchFolder/index.ts b/src/types/watchFolder/index.ts index 97fa96dceed2fb051ef2ba20b02264f9bb1a5f2b..28c8f677e293e20902dc548d8035626a6d81e175 100644 --- a/src/types/watchFolder/index.ts +++ b/src/types/watchFolder/index.ts @@ -18,3 +18,8 @@ export interface EventQueueItem { paths?: string[]; files?: ElectronFile[]; } + +export interface Lock { + wait: Promise; + unlock(): void; +} diff --git a/src/utils/common/index.ts b/src/utils/common/index.ts index 7dcd502da775c19e430bc557bf7fa60ba9cb8719..253832bc0b99285d5461aa36703fedf5e1401b92 100644 --- a/src/utils/common/index.ts +++ b/src/utils/common/index.ts @@ -1,6 +1,7 @@ import constants from 'utils/strings/constants'; import { CustomError } from 'utils/error'; import GetDeviceOS, { OS } from './deviceDetection'; +import { Lock } from 'types/watchFolder'; const DESKTOP_APP_GITHUB_DOWNLOAD_URL = 'https://github.com/ente-io/bhari-frame/releases/latest'; @@ -92,3 +93,16 @@ export function openLink(href: string, newTab?: boolean) { a.rel = 'noreferrer noopener'; a.click(); } + +export function newLock(): Lock { + let resolver: () => void = null; + const wait = new Promise((resolve) => { + resolver = resolve; + }); + return { + wait, + unlock: () => { + resolver(); + }, + }; +} From 4110ce8a3dd68dbc7652f75014ee3f8e6bca6717 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Wed, 27 Jul 2022 12:43:22 +0530 Subject: [PATCH 080/295] fix merge --- src/services/upload/uploadManager.ts | 62 ++++++++++------------------ 1 file changed, 21 insertions(+), 41 deletions(-) diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index fb2dee28e0322550f2a7cd3ae416568c4c34b475..b7256e2ae8b05154f5687d0bbeb84a2b576f64be 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -245,52 +245,25 @@ class UploadManager { if (this.isUploadPausing) { return; } + let fileTypeInfo = null; + let metadata = null; + let filePath = null; try { - const { fileTypeInfo, metadata, filePath } = - await (async () => { - if (file.size >= MAX_FILE_SIZE_SUPPORTED) { - logUploadInfo( - `${getFileNameSize( - file - )} rejected because of large size` - ); - - return { fileTypeInfo: null, metadata: null }; - } - const fileTypeInfo = - await UploadService.getFileType(file); - if (fileTypeInfo.fileType === FILE_TYPE.OTHERS) { - logUploadInfo( - `${getFileNameSize( - file - )} rejected because of unknown file format` - ); - return { fileTypeInfo, metadata: null }; - } - logUploadInfo( - ` extracting ${getFileNameSize(file)} metadata` - ); - const metadata = - (await UploadService.extractFileMetadata( - file, - collectionID, - fileTypeInfo - )) || null; - const filePath = (file as any).path as string; - return { fileTypeInfo, metadata, filePath }; - })(); - + logUploadInfo( + `metadata extraction started ${getFileNameSize(file)} ` + ); + const result = await this.extractFileTypeAndMetadata( + file, + collectionID + ); + fileTypeInfo = result.fileTypeInfo; + metadata = result.metadata; + filePath = result.filePath; logUploadInfo( `metadata extraction successful${getFileNameSize( file )} ` ); - this.metadataAndFileTypeInfoMap.set(localID, { - fileTypeInfo: fileTypeInfo && { ...fileTypeInfo }, - metadata: metadata && { ...metadata }, - filePath: filePath, - }); - UIService.increaseFileUploaded(); } catch (e) { logError(e, 'metadata extraction failed for a file'); logUploadInfo( @@ -299,6 +272,12 @@ class UploadManager { )} error: ${e.message}` ); } + this.metadataAndFileTypeInfoMap.set(localID, { + fileTypeInfo: fileTypeInfo && { ...fileTypeInfo }, + metadata: metadata && { ...metadata }, + filePath: filePath, + }); + UIService.increaseFileUploaded(); } } catch (e) { logError(e, 'error extracting metadata'); @@ -333,7 +312,8 @@ class UploadManager { collectionID, fileTypeInfo )) || null; - return { fileTypeInfo, metadata }; + const filePath = (file as any).path as string; + return { fileTypeInfo, metadata, filePath }; } private async uploadMediaFiles(mediaFiles: FileWithCollection[]) { From f852ddc84ed887e52066477ae641a28e4d5bfcb6 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Wed, 27 Jul 2022 16:36:27 +0530 Subject: [PATCH 081/295] added pausing uploads --- src/constants/upload/index.ts | 1 + src/services/upload/uploadManager.ts | 20 +++++++++++++++++--- src/utils/strings/englishConstants.tsx | 2 +- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/constants/upload/index.ts b/src/constants/upload/index.ts index 625dc7de2778f4f754581c91959aa2f34881084e..b5e8a267a6f99745dd51b88ecb84c896c4e7040b 100644 --- a/src/constants/upload/index.ts +++ b/src/constants/upload/index.ts @@ -29,6 +29,7 @@ export enum UPLOAD_STAGES { EXTRACTING_METADATA, UPLOADING, FINISH, + PAUSING, } export enum UPLOAD_STRATEGY { diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index b7256e2ae8b05154f5687d0bbeb84a2b576f64be..3aaeb5ea80e5b9274387cb568549585f81a5a1d6 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -109,6 +109,10 @@ class UploadManager { UPLOAD_STAGES.READING_GOOGLE_METADATA_FILES ); await this.parseMetadataJSONFiles(metadataJSONFiles); + if (this.isUploadPausing) { + this.uploadPausingDone(); + return; + } UploadService.setParsedMetadataJSONMap( this.parsedMetadataJSONMap ); @@ -116,6 +120,10 @@ class UploadManager { if (mediaFiles.length) { UIService.setUploadStage(UPLOAD_STAGES.EXTRACTING_METADATA); await this.extractMetadataFromFiles(mediaFiles); + if (this.isUploadPausing) { + this.uploadPausingDone(); + return; + } UploadService.setMetadataAndFileTypeInfoMap( this.metadataAndFileTypeInfoMap ); @@ -169,6 +177,10 @@ class UploadManager { ); await this.uploadMediaFiles(allFiles); + if (this.isUploadPausing) { + this.uploadPausingDone(); + return; + } } UIService.setUploadStage(UPLOAD_STAGES.FINISH); UIService.setPercentComplete(FILE_UPLOAD_COMPLETED); @@ -180,9 +192,6 @@ class UploadManager { ); throw e; } finally { - if (this.isUploadPausing) { - this.isUploadPausing = false; - } for (let i = 0; i < MAX_CONCURRENT_UPLOADS; i++) { this.cryptoWorkers[i]?.worker.terminate(); } @@ -457,9 +466,14 @@ class UploadManager { if (isElectron()) { watchFolderService.pauseService(); this.isUploadPausing = true; + UIService.setUploadStage(UPLOAD_STAGES.PAUSING); } } + private async uploadPausingDone() { + this.isUploadPausing = false; + } + private updateExistingCollections(decryptedFile: EnteFile) { if (!this.existingFilesCollectionWise.has(decryptedFile.collectionID)) { this.existingFilesCollectionWise.set( diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx index 9ce6b5ac3706975d2132fcb308f3d462654b25d1..37e58b9853c0347b58ad250623a1db3f8028807c 100644 --- a/src/utils/strings/englishConstants.tsx +++ b/src/utils/strings/englishConstants.tsx @@ -111,7 +111,7 @@ const englishConstants = { 3: (fileCounter) => `${fileCounter.finished} / ${fileCounter.total} files backed up`, 4: 'Backup complete', - 5: 'Cancelling remaining uploads', + 5: 'Pausing remaining uploads', }, UPLOADING_FILES: 'File upload', FILE_NOT_UPLOADED_LIST: 'The following files were not uploaded', From 5d519e3a969e7b37efeb526b8a8542b7497333e0 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Wed, 10 Aug 2022 14:21:25 +0530 Subject: [PATCH 082/295] fix modal width --- src/components/DialogBox/base.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/DialogBox/base.tsx b/src/components/DialogBox/base.tsx index 6db198c753ee35f695740d6f169d07b86af221cc..bc3362daa3ec407020d30bf1e7c6292e88acc41e 100644 --- a/src/components/DialogBox/base.tsx +++ b/src/components/DialogBox/base.tsx @@ -1,9 +1,9 @@ import { Dialog, styled } from '@mui/material'; -const DialogBoxBase = styled(Dialog)(({ theme }) => ({ +const DialogBoxBase = styled(Dialog)(({ theme, maxWidth }) => ({ '& .MuiDialog-paper': { padding: theme.spacing(1, 1.5), - maxWidth: '346px', + maxWidth: maxWidth ?? '346px', }, '& .MuiDialogTitle-root': { padding: theme.spacing(2), From a01789100455b628d64c289659fd5f32c365ab03 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Wed, 10 Aug 2022 14:24:26 +0530 Subject: [PATCH 083/295] added more conditions to handle paused uploads --- src/constants/upload/index.ts | 1 + src/services/upload/fileService.ts | 8 +++++++ src/services/upload/livePhotoService.ts | 3 +++ src/services/upload/multiPartUploadService.ts | 4 ++++ src/services/upload/uploadManager.ts | 23 +++++++++++-------- src/services/upload/uploadService.ts | 17 +++++++++++++- src/services/upload/uploader.ts | 2 ++ src/types/upload/index.ts | 4 ++++ src/utils/error/index.ts | 1 + 9 files changed, 53 insertions(+), 10 deletions(-) diff --git a/src/constants/upload/index.ts b/src/constants/upload/index.ts index b5e8a267a6f99745dd51b88ecb84c896c4e7040b..37c54215fed1bde4d92a987d781683f1458c023d 100644 --- a/src/constants/upload/index.ts +++ b/src/constants/upload/index.ts @@ -47,6 +47,7 @@ export enum UPLOAD_RESULT { UPLOADED, UPLOADED_WITH_STATIC_THUMBNAIL, ADDED_SYMLINK, + PAUSED, } export const MAX_FILE_SIZE_SUPPORTED = 4 * 1024 * 1024 * 1024; // 4 GB diff --git a/src/services/upload/fileService.ts b/src/services/upload/fileService.ts index 939e769e6521cf462cd7b4dbb45283e755f26a90..38e0011a6e9c56f2043698f7f7f350f8c7403088 100644 --- a/src/services/upload/fileService.ts +++ b/src/services/upload/fileService.ts @@ -22,6 +22,8 @@ import { getUint8ArrayView, } from '../readerService'; import { generateThumbnail } from './thumbnailService'; +import uploadService from './uploadService'; +import { CustomError } from 'utils/error'; const EDITED_FILE_SUFFIX = '-edited'; @@ -37,6 +39,9 @@ export async function readFile( fileTypeInfo: FileTypeInfo, rawFile: File | ElectronFile ): Promise { + if (uploadService.isUploadPausing()) { + throw Error(CustomError.UPLOAD_PAUSED); + } const { thumbnail, hasStaticThumbnail } = await generateThumbnail( rawFile, fileTypeInfo @@ -98,6 +103,9 @@ export async function encryptFile( encryptionKey: string ): Promise { try { + if (uploadService.isUploadPausing()) { + throw Error(CustomError.UPLOAD_PAUSED); + } const { key: fileKey, file: encryptedFiledata } = await encryptFiledata( worker, file.filedata diff --git a/src/services/upload/livePhotoService.ts b/src/services/upload/livePhotoService.ts index 1b2000cc1bc03452f80cad9e453080dc53c07978..e68a2f0ee637f50de0d57d823236d3d1fcb4cbbf 100644 --- a/src/services/upload/livePhotoService.ts +++ b/src/services/upload/livePhotoService.ts @@ -79,6 +79,9 @@ export async function readLivePhoto( fileTypeInfo: FileTypeInfo, livePhotoAssets: LivePhotoAssets ) { + if (uploadService.isUploadPausing()) { + throw Error(CustomError.UPLOAD_PAUSED); + } const { thumbnail, hasStaticThumbnail } = await generateThumbnail( livePhotoAssets.image, { diff --git a/src/services/upload/multiPartUploadService.ts b/src/services/upload/multiPartUploadService.ts index 4b7070398fe2ef736dc9cf4e3f7c6b0a461c559b..638044a024fab3cb817f5b5ee5b561d6d4ea6ffd 100644 --- a/src/services/upload/multiPartUploadService.ts +++ b/src/services/upload/multiPartUploadService.ts @@ -8,6 +8,7 @@ import UploadHttpClient from './uploadHttpClient'; import * as convert from 'xml-js'; import { CustomError } from 'utils/error'; import { DataStream, MultipartUploadURLs } from 'types/upload'; +import uploadService from './uploadService'; interface PartEtag { PartNumber: number; @@ -51,6 +52,9 @@ export async function uploadStreamInParts( index, fileUploadURL, ] of multipartUploadURLs.partURLs.entries()) { + if (uploadService.isUploadPausing()) { + throw Error(CustomError.UPLOAD_PAUSED); + } const uploadChunk = await combineChunksToFormUploadPart(streamReader); const progressTracker = UIService.trackUploadProgress( fileLocalID, diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index 9c2cbee28aea73c6d0e0ee2f62e8b60183cc6667..951f57bce9dcf115b24a3b1af71886ee52cb81b9 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -27,6 +27,7 @@ import { EnteFile } from 'types/file'; import { ElectronFile, FileWithCollection, + IsUploadPausing, Metadata, MetadataAndFileTypeInfo, MetadataAndFileTypeInfoMap, @@ -61,7 +62,9 @@ class UploadManager { private existingFiles: EnteFile[]; private setFiles: SetFiles; private collections: Map; - private isUploadPausing: boolean = false; + private isUploadPausing: IsUploadPausing = { + val: false, + }; public initUploader(progressUpdater: ProgressUpdater, setFiles: SetFiles) { UIService.init(progressUpdater); this.setFiles = setFiles; @@ -107,7 +110,7 @@ class UploadManager { UPLOAD_STAGES.READING_GOOGLE_METADATA_FILES ); await this.parseMetadataJSONFiles(metadataJSONFiles); - if (this.isUploadPausing) { + if (this.isUploadPausing.val) { this.uploadPausingDone(); return; } @@ -118,7 +121,7 @@ class UploadManager { if (mediaFiles.length) { UIService.setUploadStage(UPLOAD_STAGES.EXTRACTING_METADATA); await this.extractMetadataFromFiles(mediaFiles); - if (this.isUploadPausing) { + if (this.isUploadPausing.val) { this.uploadPausingDone(); return; } @@ -175,7 +178,7 @@ class UploadManager { ); await this.uploadMediaFiles(allFiles); - if (this.isUploadPausing) { + if (this.isUploadPausing.val) { this.uploadPausingDone(); return; } @@ -204,7 +207,7 @@ class UploadManager { for (const { file, collectionID } of metadataFiles) { try { - if (this.isUploadPausing) { + if (this.isUploadPausing.val) { return; } @@ -249,7 +252,7 @@ class UploadManager { addLogLine(`extractMetadataFromFiles executed`); UIService.reset(mediaFiles.length); for (const { file, localID, collectionID } of mediaFiles) { - if (this.isUploadPausing) { + if (this.isUploadPausing.val) { return; } let fileTypeInfo = null; @@ -366,7 +369,7 @@ class UploadManager { private async uploadNextFileInQueue(worker: any) { while (this.filesToBeUploaded.length > 0) { - if (this.isUploadPausing) { + if (this.isUploadPausing.val) { return; } let fileWithCollection = this.filesToBeUploaded.pop(); @@ -470,13 +473,15 @@ class UploadManager { public pauseWatchService() { if (isElectron()) { watchFolderService.pauseService(); - this.isUploadPausing = true; + this.isUploadPausing.val = true; + UploadService.setUploadPausing(true); UIService.setUploadStage(UPLOAD_STAGES.PAUSING); } } private async uploadPausingDone() { - this.isUploadPausing = false; + this.isUploadPausing.val = false; + UploadService.setUploadPausing(false); } private updateExistingCollections(decryptedFile: EnteFile) { diff --git a/src/services/upload/uploadService.ts b/src/services/upload/uploadService.ts index 3234dd95138e5be5effd8ba402bdbb55c9f5b97f..f96517555c27c63dfa7876894a67d54f1f65dba6 100644 --- a/src/services/upload/uploadService.ts +++ b/src/services/upload/uploadService.ts @@ -3,7 +3,7 @@ import { logError } from 'utils/sentry'; import UploadHttpClient from './uploadHttpClient'; import { extractFileMetadata, getFilename } from './fileService'; import { getFileType } from '../typeDetectionService'; -import { handleUploadError } from 'utils/error'; +import { CustomError, handleUploadError } from 'utils/error'; import { B64EncryptionResult, BackupedFile, @@ -13,6 +13,7 @@ import { FileWithCollection, FileWithMetadata, isDataStream, + IsUploadPausing, Metadata, MetadataAndFileTypeInfo, MetadataAndFileTypeInfoMap, @@ -44,6 +45,9 @@ class UploadService { number, MetadataAndFileTypeInfo >(); + private uploadPausing: IsUploadPausing = { + val: false, + }; private pendingUploadCount: number = 0; async setFileCount(fileCount: number) { @@ -77,6 +81,14 @@ class UploadService { : getFilename(file); } + setUploadPausing(isPausing: boolean) { + this.uploadPausing.val = isPausing; + } + + isUploadPausing(): boolean { + return this.uploadPausing.val; + } + async getFileType(file: File | ElectronFile) { return getFileType(file); } @@ -131,6 +143,9 @@ class UploadService { async uploadToBucket(file: ProcessedFile): Promise { try { + if (this.isUploadPausing()) { + throw Error(CustomError.UPLOAD_PAUSED); + } let fileObjectKey: string = null; if (isDataStream(file.file.encryptedData)) { fileObjectKey = await uploadStreamUsingMultipart( diff --git a/src/services/upload/uploader.ts b/src/services/upload/uploader.ts index 624fdfd81842b7e5d951111a0be0e4a89565b3cc..9ff5c45b5d0728a80c0632ed2fb1e688e1bbacbf 100644 --- a/src/services/upload/uploader.ts +++ b/src/services/upload/uploader.ts @@ -149,6 +149,8 @@ export default async function uploader( }); const error = handleUploadError(e); switch (error.message) { + case CustomError.UPLOAD_PAUSED: + return { fileUploadResult: UPLOAD_RESULT.PAUSED }; case CustomError.ETAG_MISSING: return { fileUploadResult: UPLOAD_RESULT.BLOCKED }; case CustomError.UNSUPPORTED_FILE_FORMAT: diff --git a/src/types/upload/index.ts b/src/types/upload/index.ts index f42d5ead6b54da0d3f08622e94cda921df44b21d..4c185dd047e51d581966b271e54b2d7ab9b28978 100644 --- a/src/types/upload/index.ts +++ b/src/types/upload/index.ts @@ -143,3 +143,7 @@ export interface ParsedExtractedMetadata { location: Location; creationTime: number; } + +export interface IsUploadPausing { + val: boolean; +} diff --git a/src/utils/error/index.ts b/src/utils/error/index.ts index eb3117ffc289b3d89759db8d68d8b70550712ae9..d115716fcead003da01bcba6e3455e3094c517bd 100644 --- a/src/utils/error/index.ts +++ b/src/utils/error/index.ts @@ -45,6 +45,7 @@ export enum CustomError { FILE_ID_NOT_FOUND = 'file with id not found', WEAK_DEVICE = 'password decryption failed on the device', INCORRECT_PASSWORD = 'incorrect password', + UPLOAD_PAUSED = 'upload paused', } function parseUploadErrorCodes(error) { From 0559812506d2aa7e498769ef72e95635e7871fcb Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 16 Aug 2022 11:48:12 +0530 Subject: [PATCH 084/295] revert change to DialogBoxBase --- src/components/DialogBox/base.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/DialogBox/base.tsx b/src/components/DialogBox/base.tsx index bc3362daa3ec407020d30bf1e7c6292e88acc41e..6db198c753ee35f695740d6f169d07b86af221cc 100644 --- a/src/components/DialogBox/base.tsx +++ b/src/components/DialogBox/base.tsx @@ -1,9 +1,9 @@ import { Dialog, styled } from '@mui/material'; -const DialogBoxBase = styled(Dialog)(({ theme, maxWidth }) => ({ +const DialogBoxBase = styled(Dialog)(({ theme }) => ({ '& .MuiDialog-paper': { padding: theme.spacing(1, 1.5), - maxWidth: maxWidth ?? '346px', + maxWidth: '346px', }, '& .MuiDialogTitle-root': { padding: theme.spacing(2), From a2cf90992d2b74bf978ac0472b174415d95ef17a Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 16 Aug 2022 12:26:36 +0530 Subject: [PATCH 085/295] update watch no mapping content ui --- src/components/WatchFolder/index.tsx | 64 ++++++++++--------- .../WatchFolder/styledComponents.tsx | 1 - src/pages/_app.tsx | 2 +- src/pages/gallery/index.tsx | 2 +- 4 files changed, 37 insertions(+), 32 deletions(-) diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index 2f6825975aa213a8ca525e278db948190033a38d..a3fe616ff8c2b0a137d08b87187af3cc0088c877 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -1,12 +1,11 @@ import { MappingList } from './mappingList'; import { NoMappingsContent } from './noMappingsContent'; import React, { useContext, useEffect, useState } from 'react'; -import { Button, DialogActions, DialogContent } from '@mui/material'; +import { Button, Dialog, DialogContent, Stack } from '@mui/material'; import watchFolderService from 'services/watchFolder/watchFolderService'; import { WatchMapping } from 'types/watchFolder'; import { AppContext } from 'pages/_app'; import constants from 'utils/strings/constants'; -import DialogBoxBase from 'components/DialogBox/base'; import DialogTitleWithCloseButton from 'components/DialogBox/TitleWithCloseButton'; import UploadStrategyChoiceModal from 'components/Upload/UploadStrategyChoiceModal'; import { UPLOAD_STRATEGY } from 'constants/upload'; @@ -87,36 +86,43 @@ export default function WatchFolder({ open, onClose }: Iprops) { return ( <> - - + + {constants.WATCHED_FOLDERS} - - {mappings.length === 0 ? ( - - ) : ( - - )} - + + + {mappings.length === 0 ? ( + + ) : ( + + )} - - - - + + + + ({ })); export const NoMappingsContainer = styled(VerticallyCentered)({ - height: '278px', textAlign: 'left', alignItems: 'flex-start', }); diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index ed219cfd27d85a3c85ab85e6197802e5a067f6a5..d53e74c45fb4c1ab084c65da09dff8a61eadd376 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -94,7 +94,7 @@ export default function App({ Component, err }) { const [dialogMessage, setDialogMessage] = useState(); const [messageDialogView, setMessageDialogView] = useState(false); const [isFolderSyncRunning, setIsFolderSyncRunning] = useState(false); - const [watchFolderView, setWatchFolderView] = useState(false); + const [watchFolderView, setWatchFolderView] = useState(true); const [watchFolderFiles, setWatchFolderFiles] = useState(null); const isMobile = useMediaQuery('(max-width:428px)'); diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index 7bf1172d7e02e6197e42f54bf5dbc7fc37b983b6..9457e02748c99c6d10606b20ed3c611b001b01e5 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -207,7 +207,7 @@ export default function Gallery() { const [webFiles, setWebFiles] = useState([]); const [uploadTypeSelectorView, setUploadTypeSelectorView] = useState(false); - const [sidebarView, setSidebarView] = useState(false); + const [sidebarView, setSidebarView] = useState(true); const closeSidebar = () => setSidebarView(false); const openSidebar = () => setSidebarView(true); From 153a2e49b9d454721c96bde584500f6e2593c070 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 16 Aug 2022 12:32:51 +0530 Subject: [PATCH 086/295] refactor, move, rename --- src/components/Sidebar/UtilitySection.tsx | 30 +++++++---------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/src/components/Sidebar/UtilitySection.tsx b/src/components/Sidebar/UtilitySection.tsx index 599fada0cc0c3ee555976eecb519741a2e2e90c3..53a90e4926630c2fec5a531e12858d3fd9adb591 100644 --- a/src/components/Sidebar/UtilitySection.tsx +++ b/src/components/Sidebar/UtilitySection.tsx @@ -8,8 +8,8 @@ import { PAGES } from 'constants/pages'; import { useRouter } from 'next/router'; import { AppContext } from 'pages/_app'; import isElectron from 'is-electron'; -import { downloadApp } from 'utils/common'; import WatchFolder from 'components/WatchFolder'; +import { getDownloadAppMessage } from 'utils/ui'; export default function UtilitySection({ closeSidebar }) { const router = useRouter(); @@ -27,28 +27,17 @@ export default function UtilitySection({ closeSidebar }) { const openRecoveryKeyModal = () => setRecoveryModalView(true); const closeRecoveryKeyModal = () => setRecoveryModalView(false); - const openTwoFactorModalView = () => setTwoFactorModalView(true); - const closeTwoFactorModalView = () => setTwoFactorModalView(false); + const openTwoFactorModal = () => setTwoFactorModalView(true); + const closeTwoFactorModal = () => setTwoFactorModalView(false); - const openWatchFolderView = () => { + const openWatchFolder = () => { if (isElectron()) { setWatchFolderView(true); } else { - setDialogMessage({ - title: constants.DOWNLOAD_APP, - content: constants.DOWNLOAD_APP_MESSAGE, - - proceed: { - text: constants.DOWNLOAD, - action: downloadApp, - variant: 'accent', - }, - close: { - text: constants.CLOSE, - }, - }); + setDialogMessage(getDownloadAppMessage()); } }; + const closeWatchFolder = () => setWatchFolderView(false); const redirectToChangePasswordPage = () => { closeSidebar(); @@ -71,13 +60,12 @@ export default function UtilitySection({ closeSidebar }) { close: { variant: 'danger' }, }); - const closeWatchFolder = () => setWatchFolderView(false); return ( <> {constants.RECOVERY_KEY} - + {constants.TWO_FACTOR} @@ -89,7 +77,7 @@ export default function UtilitySection({ closeSidebar }) { {constants.DEDUPLICATE_FILES} - + {constants.WATCH_FOLDERS} @@ -104,7 +92,7 @@ export default function UtilitySection({ closeSidebar }) { /> From 15dec7a8ea3d8a3155beb1b6cdc528295178615e Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 16 Aug 2022 12:55:02 +0530 Subject: [PATCH 087/295] refactor closeUploadProgress --- src/components/Upload/Uploader.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/Upload/Uploader.tsx b/src/components/Upload/Uploader.tsx index 82f37d3ad13ede1b1883c1122f063303f8ec95a2..60a1cc3e91bd3ea38024878c5d06d32ef44dbc8e 100644 --- a/src/components/Upload/Uploader.tsx +++ b/src/components/Upload/Uploader.tsx @@ -108,6 +108,8 @@ export default function Uploader(props: Props) { const uploadType = useRef(null); const zipPaths = useRef(null); + const closeUploadProgress = () => setUploadProgressView(false); + useEffect(() => { UploadManager.initUploader( { @@ -312,7 +314,7 @@ export default function Uploader(props: Props) { ); } } catch (e) { - setUploadProgressView(false); + closeUploadProgress(); logError(e, 'Failed to create album'); appContext.setDialogMessage({ title: constants.ERROR, @@ -359,7 +361,7 @@ export default function Uploader(props: Props) { ); } catch (err) { showUserFacingError(err.message); - setUploadProgressView(false); + closeUploadProgress(); throw err; } finally { props.setUploadInProgress(false); @@ -376,7 +378,7 @@ export default function Uploader(props: Props) { } catch (err) { showUserFacingError(err.message); - setUploadProgressView(false); + closeUploadProgress(); } finally { props.setUploadInProgress(false); props.syncWithRemote(); @@ -507,7 +509,7 @@ export default function Uploader(props: Props) { }; const cancelUploads = async () => { - setUploadProgressView(false); + closeUploadProgress(); if (isElectron()) { ImportService.cancelRemainingUploads(); } @@ -515,8 +517,6 @@ export default function Uploader(props: Props) { Router.reload(); }; - const closeUploadProgress = () => setUploadProgressView(false); - const handleUpload = (type) => () => { if (isElectron() && importService.checkAllElectronAPIsExists()) { handleDesktopUpload(type); From e76217a051b0c81d5557253af554365042abc37d Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 16 Aug 2022 13:00:32 +0530 Subject: [PATCH 088/295] don't need to use expanded prop to show Snackbar as its already managed by UploadProgress component --- src/components/Upload/UploadProgress/minimized.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Upload/UploadProgress/minimized.tsx b/src/components/Upload/UploadProgress/minimized.tsx index c314dcd98e2e7098835e84259dfd558a6bd0917c..1d860083ffff05cf22a65598b984659130378225 100644 --- a/src/components/Upload/UploadProgress/minimized.tsx +++ b/src/components/Upload/UploadProgress/minimized.tsx @@ -1,10 +1,10 @@ import { Snackbar, Paper } from '@mui/material'; import React from 'react'; import { UploadProgressHeader } from './header'; -export function MinimizedUploadProgress(props) { +export function MinimizedUploadProgress() { return ( Date: Tue, 16 Aug 2022 12:55:02 +0530 Subject: [PATCH 089/295] refactor closeUploadProgress --- src/components/Upload/Uploader.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/Upload/Uploader.tsx b/src/components/Upload/Uploader.tsx index 8bfcdb6ed3c239a51311f9529dc3dbe09fe0fd0d..b636424bcddacf664b945d76dfb0098de1d2610e 100644 --- a/src/components/Upload/Uploader.tsx +++ b/src/components/Upload/Uploader.tsx @@ -118,6 +118,8 @@ export default function Uploader(props: Props) { const waitForPrevUpload = useRef>(null); const uploadDone = useRef<() => void>(null); + const closeUploadProgress = () => setUploadProgressView(false); + useEffect(() => { UploadManager.initUploader( { @@ -339,7 +341,7 @@ export default function Uploader(props: Props) { ); } } catch (e) { - setUploadProgressView(false); + closeUploadProgress(); logError(e, 'Failed to create album'); appContext.setDialogMessage({ title: constants.ERROR, @@ -390,7 +392,7 @@ export default function Uploader(props: Props) { ); } catch (err) { showUserFacingError(err.message); - setUploadProgressView(false); + closeUploadProgress(); throw err; } finally { unsetUploadLock(); @@ -432,7 +434,7 @@ export default function Uploader(props: Props) { } catch (err) { showUserFacingError(err.message); - setUploadProgressView(false); + closeUploadProgress(); } finally { props.setUploadInProgress(false); props.syncWithRemote(); @@ -563,7 +565,7 @@ export default function Uploader(props: Props) { }; const cancelUploads = async () => { - setUploadProgressView(false); + closeUploadProgress(); if (isElectron()) { ImportService.cancelRemainingUploads(); } @@ -571,8 +573,6 @@ export default function Uploader(props: Props) { Router.reload(); }; - const closeUploadProgress = () => setUploadProgressView(false); - const handleUpload = (type) => () => { if (isElectron() && importService.checkAllElectronAPIsExists()) { handleDesktopUpload(type); From 6cc326384fe60e3690760b457cfc16b4664ad98a Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 16 Aug 2022 13:00:32 +0530 Subject: [PATCH 090/295] don't need to use expanded prop to show Snackbar as its already managed by UploadProgress component --- src/components/Upload/UploadProgress/minimized.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/components/Upload/UploadProgress/minimized.tsx b/src/components/Upload/UploadProgress/minimized.tsx index db33986774d999a75c71c8072611d784d6f45c07..1d860083ffff05cf22a65598b984659130378225 100644 --- a/src/components/Upload/UploadProgress/minimized.tsx +++ b/src/components/Upload/UploadProgress/minimized.tsx @@ -1,12 +1,10 @@ import { Snackbar, Paper } from '@mui/material'; -import UploadProgressContext from 'contexts/uploadProgress'; -import React, { useContext } from 'react'; +import React from 'react'; import { UploadProgressHeader } from './header'; export function MinimizedUploadProgress() { - const { open } = useContext(UploadProgressContext); return ( Date: Tue, 16 Aug 2022 13:15:49 +0530 Subject: [PATCH 091/295] made prebuild as a caller of actual microtask yarn lint --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index fb90582a03d2a2ea7d3ff89d2f07082d4fa78d31..86b9469492f9293a25bebd963e6be76849420c34 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,11 @@ "scripts": { "dev": "next dev", "albums": "next dev -p 3002", - "prebuild": "eslint \"src/**/*.{js,jsx,ts,tsx}\"", + "lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"", + "prebuild": "yarn lint", "build": "next build", - "build-analyze": "ANALYZE=true next build", "postbuild": "next export", + "build-analyze": "ANALYZE=true next build", "start": "next start", "prepare": "husky install" }, From 73484eac2cdd6785b4447e08c4ec6ee89f4bb560 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 16 Aug 2022 12:38:50 +0530 Subject: [PATCH 092/295] add comment --- src/components/Upload/UploadProgress/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Upload/UploadProgress/index.tsx b/src/components/Upload/UploadProgress/index.tsx index 4ecc45b59b907293156ed5a8f6ac2025f37630a3..5d538f0cb4f72d1c9e5f0166ce19bf365d7cd4e6 100644 --- a/src/components/Upload/UploadProgress/index.tsx +++ b/src/components/Upload/UploadProgress/index.tsx @@ -43,6 +43,7 @@ export default function UploadProgress({ const appContext = useContext(AppContext); const [expanded, setExpanded] = useState(true); + // run watch folder minimized by default useEffect(() => { if ( appContext.isFolderSyncRunning && From 6d8528cdc8f83999a3be04e80951a6c321fcda77 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 16 Aug 2022 19:35:52 +0530 Subject: [PATCH 093/295] change lock system to queue system --- src/components/Upload/Uploader.tsx | 47 ++++++++++++------------------ src/types/watchFolder/index.ts | 5 ---- src/utils/common/index.ts | 25 ++++++++-------- 3 files changed, 32 insertions(+), 45 deletions(-) diff --git a/src/components/Upload/Uploader.tsx b/src/components/Upload/Uploader.tsx index b636424bcddacf664b945d76dfb0098de1d2610e..4ee5ed203625147b446a5dc3a9ffd8cede6a5efb 100644 --- a/src/components/Upload/Uploader.tsx +++ b/src/components/Upload/Uploader.tsx @@ -21,7 +21,7 @@ import { SetLoading, SetFiles } from 'types/gallery'; import { ElectronFile, FileWithCollection } from 'types/upload'; import Router from 'next/router'; import { isCanvasBlocked } from 'utils/upload/isCanvasBlocked'; -import { downloadApp } from 'utils/common'; +import { downloadApp, waitAndRun } from 'utils/common'; import watchFolderService from 'services/watchFolder/watchFolderService'; import DiscFullIcon from '@mui/icons-material/DiscFull'; import { NotificationAttributes } from 'types/Notification'; @@ -35,7 +35,6 @@ import { UPLOAD_STAGES } from 'constants/upload'; import importService from 'services/importService'; import { getDownloadAppMessage } from 'utils/ui'; import UploadTypeSelector from './UploadTypeSelector'; -import { newLock } from 'utils/common'; const FIRST_ALBUM_NAME = 'My First Album'; @@ -61,12 +60,6 @@ interface Props { showUploadDirsDialog: () => void; } -export enum DESKTOP_UPLOAD_TYPE { - FILES = 'files', - FOLDERS = 'folders', - ZIPS = 'zips', -} - enum UPLOAD_STRATEGY { SINGLE_COLLECTION, COLLECTION_PER_FOLDER, @@ -115,8 +108,7 @@ export default function Uploader(props: Props) { const pendingDesktopUploadCollectionName = useRef(''); const uploadType = useRef(null); const zipPaths = useRef(null); - const waitForPrevUpload = useRef>(null); - const uploadDone = useRef<() => void>(null); + const previousUploadPromise = useRef>(null); const closeUploadProgress = () => setUploadProgressView(false); @@ -300,7 +292,9 @@ export default function Uploader(props: Props) { localID: index, collectionID: collection.id, })); - await uploadFiles(filesWithCollectionToUpload, [collection]); + await waitInQueueAndUploadFiles(filesWithCollectionToUpload, [ + collection, + ]); } catch (e) { logError(e, 'Failed to upload files to existing collections'); } @@ -351,21 +345,30 @@ export default function Uploader(props: Props) { }); throw e; } - await uploadFiles(filesWithCollectionToUpload, collections); + await waitInQueueAndUploadFiles( + filesWithCollectionToUpload, + collections + ); } catch (e) { logError(e, 'Failed to upload files to new collections'); } }; + const waitInQueueAndUploadFiles = async ( + filesWithCollectionToUpload: FileWithCollection[], + collections: Collection[] + ) => { + const currentPromise = previousUploadPromise.current; + previousUploadPromise.current = waitAndRun(currentPromise, () => + uploadFiles(filesWithCollectionToUpload, collections) + ); + }; + const uploadFiles = async ( filesWithCollectionToUpload: FileWithCollection[], collections: Collection[] ) => { try { - if (waitForPrevUpload.current !== null) { - await waitForPrevUpload.current; // wait for previous upload to finish - } - setUploadLock(); uploadInit(); props.setUploadInProgress(true); props.closeCollectionSelector(); @@ -395,7 +398,6 @@ export default function Uploader(props: Props) { closeUploadProgress(); throw err; } finally { - unsetUploadLock(); props.setUploadInProgress(false); props.syncWithRemote(); if (isElectron()) { @@ -414,17 +416,6 @@ export default function Uploader(props: Props) { } }; - const setUploadLock = () => { - const { wait, unlock } = newLock(); - waitForPrevUpload.current = wait; - uploadDone.current = unlock; - }; - - const unsetUploadLock = () => { - uploadDone.current(); - waitForPrevUpload.current = null; - }; - const retryFailed = async () => { try { props.setUploadInProgress(true); diff --git a/src/types/watchFolder/index.ts b/src/types/watchFolder/index.ts index 28c8f677e293e20902dc548d8035626a6d81e175..97fa96dceed2fb051ef2ba20b02264f9bb1a5f2b 100644 --- a/src/types/watchFolder/index.ts +++ b/src/types/watchFolder/index.ts @@ -18,8 +18,3 @@ export interface EventQueueItem { paths?: string[]; files?: ElectronFile[]; } - -export interface Lock { - wait: Promise; - unlock(): void; -} diff --git a/src/utils/common/index.ts b/src/utils/common/index.ts index 253832bc0b99285d5461aa36703fedf5e1401b92..0e71519e6404c1580484174830d11dc2bc0aa2da 100644 --- a/src/utils/common/index.ts +++ b/src/utils/common/index.ts @@ -1,7 +1,6 @@ import constants from 'utils/strings/constants'; import { CustomError } from 'utils/error'; import GetDeviceOS, { OS } from './deviceDetection'; -import { Lock } from 'types/watchFolder'; const DESKTOP_APP_GITHUB_DOWNLOAD_URL = 'https://github.com/ente-io/bhari-frame/releases/latest'; @@ -94,15 +93,17 @@ export function openLink(href: string, newTab?: boolean) { a.click(); } -export function newLock(): Lock { - let resolver: () => void = null; - const wait = new Promise((resolve) => { - resolver = resolve; - }); - return { - wait, - unlock: () => { - resolver(); - }, - }; +export async function waitAndRun(waitPromise: Promise, task: () => void) { + if (waitPromise && isPromise(waitPromise)) { + await waitPromise; + } + task(); +} + +function isPromise(p: any) { + if (typeof p === 'object' && typeof p.then === 'function') { + return true; + } + + return false; } From 008e6b5d36e347860958e5af51e48af17c69b8e5 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 16 Aug 2022 19:40:08 +0530 Subject: [PATCH 094/295] need to run also if running watch service upload was paused --- src/components/Upload/Uploader.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Upload/Uploader.tsx b/src/components/Upload/Uploader.tsx index 4ee5ed203625147b446a5dc3a9ffd8cede6a5efb..cb360aa05b30b9cff3daf5c78ee595be19bc49c4 100644 --- a/src/components/Upload/Uploader.tsx +++ b/src/components/Upload/Uploader.tsx @@ -161,7 +161,8 @@ export default function Uploader(props: Props) { // a user upload is already in progress return; } - } else if (isCanvasBlocked()) { + } + if (isCanvasBlocked()) { appContext.setDialogMessage({ title: constants.CANVAS_BLOCKED_TITLE, From 1c2a03ba5ec625cb5d106662b5c25ceba3196398 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 16 Aug 2022 19:41:11 +0530 Subject: [PATCH 095/295] move code --- src/components/Upload/Uploader.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/Upload/Uploader.tsx b/src/components/Upload/Uploader.tsx index cb360aa05b30b9cff3daf5c78ee595be19bc49c4..a1a2a82ad1d58e659afe7b5e9b3c92aad5a460c0 100644 --- a/src/components/Upload/Uploader.tsx +++ b/src/components/Upload/Uploader.tsx @@ -112,6 +112,11 @@ export default function Uploader(props: Props) { const closeUploadProgress = () => setUploadProgressView(false); + const setCollectionName = (collectionName: string) => { + isPendingDesktopUpload.current = true; + pendingDesktopUploadCollectionName.current = collectionName; + }; + useEffect(() => { UploadManager.initUploader( { @@ -141,11 +146,6 @@ export default function Uploader(props: Props) { } }, []); - const setCollectionName = (collectionName: string) => { - isPendingDesktopUpload.current = true; - pendingDesktopUploadCollectionName.current = collectionName; - }; - useEffect(() => { if ( props.electronFiles?.length > 0 || From 4b37a0166658322b7faf1d93da764402882a996b Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 17 Aug 2022 10:26:16 +0530 Subject: [PATCH 096/295] moved post upload complete action to uploadManager and rename --- src/components/Upload/Uploader.tsx | 23 +++++------------------ src/services/upload/uploadManager.ts | 17 ++++++++++++++--- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/components/Upload/Uploader.tsx b/src/components/Upload/Uploader.tsx index a1a2a82ad1d58e659afe7b5e9b3c92aad5a460c0..f39a4e0dde8e16991d8e63c2bac70ba7c1f07a03 100644 --- a/src/components/Upload/Uploader.tsx +++ b/src/components/Upload/Uploader.tsx @@ -356,17 +356,17 @@ export default function Uploader(props: Props) { }; const waitInQueueAndUploadFiles = async ( - filesWithCollectionToUpload: FileWithCollection[], + filesWithCollectionToUploadIn: FileWithCollection[], collections: Collection[] ) => { const currentPromise = previousUploadPromise.current; previousUploadPromise.current = waitAndRun(currentPromise, () => - uploadFiles(filesWithCollectionToUpload, collections) + uploadFiles(filesWithCollectionToUploadIn, collections) ); }; const uploadFiles = async ( - filesWithCollectionToUpload: FileWithCollection[], + filesWithCollectionToUploadIn: FileWithCollection[], collections: Collection[] ) => { try { @@ -385,13 +385,13 @@ export default function Uploader(props: Props) { } await ImportService.setToUploadFiles( UPLOAD_TYPE.FILES, - filesWithCollectionToUpload.map( + filesWithCollectionToUploadIn.map( ({ file }) => (file as ElectronFile).path ) ); } await uploadManager.queueFilesForUpload( - filesWithCollectionToUpload, + filesWithCollectionToUploadIn, collections ); } catch (err) { @@ -401,19 +401,6 @@ export default function Uploader(props: Props) { } finally { props.setUploadInProgress(false); props.syncWithRemote(); - if (isElectron()) { - if (watchFolderService.isUploadRunning()) { - await watchFolderService.allFileUploadsDone( - filesWithCollectionToUpload, - collections - ); - } else { - if (watchFolderService.isServicePaused()) { - // resume the service after user upload is done - watchFolderService.resumeService(); - } - } - } } }; diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index 951f57bce9dcf115b24a3b1af71886ee52cb81b9..f551498abf583d1de64a719d91e5f8f5012c2db0 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -93,16 +93,16 @@ class UploadManager { } public async queueFilesForUpload( - fileWithCollectionToBeUploaded: FileWithCollection[], + filesWithCollectionToUploadIn: FileWithCollection[], collections: Collection[] ) { try { await this.init(collections); addLogLine( - `received ${fileWithCollectionToBeUploaded.length} files to upload` + `received ${filesWithCollectionToUploadIn.length} files to upload` ); const { metadataJSONFiles, mediaFiles } = - segregateMetadataAndMediaFiles(fileWithCollectionToBeUploaded); + segregateMetadataAndMediaFiles(filesWithCollectionToUploadIn); addLogLine(`has ${metadataJSONFiles.length} metadata json files`); addLogLine(`has ${mediaFiles.length} media files`); if (metadataJSONFiles.length) { @@ -196,6 +196,17 @@ class UploadManager { for (let i = 0; i < MAX_CONCURRENT_UPLOADS; i++) { this.cryptoWorkers[i]?.worker.terminate(); } + if (isElectron()) { + if (watchFolderService.isUploadRunning()) { + await watchFolderService.allFileUploadsDone( + filesWithCollectionToUploadIn, + collections + ); + } else if (watchFolderService.isServicePaused()) { + // resume the service after user upload is done + watchFolderService.resumeService(); + } + } } } From ab7427c644d0f4edab1416a722f8eea153318410 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 17 Aug 2022 10:32:00 +0530 Subject: [PATCH 097/295] fix typo --- src/components/WatchFolder/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index a3fe616ff8c2b0a137d08b87187af3cc0088c877..227672c1124046b9459b4dff1de2762b99f363f8 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -18,7 +18,7 @@ interface Iprops { export default function WatchFolder({ open, onClose }: Iprops) { const [mappings, setMappings] = useState([]); const [inputFolderPath, setInputFolderPath] = useState(''); - const [choicModalOpen, setChoiceModalOpen] = useState(false); + const [choiceModalOpen, setChoiceModalOpen] = useState(false); const appContext = useContext(AppContext); useEffect(() => { @@ -124,7 +124,7 @@ export default function WatchFolder({ open, onClose }: Iprops) { Date: Wed, 17 Aug 2022 10:32:41 +0530 Subject: [PATCH 098/295] clean code --- src/components/WatchFolder/checkmarkIcon.tsx | 2 +- .../WatchFolder/mappingEntry/entryHeading.tsx | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/components/WatchFolder/checkmarkIcon.tsx b/src/components/WatchFolder/checkmarkIcon.tsx index 75805d9c94420be1df6fa1eacb53a47b9d1ed48a..10b4f0459262352012896e55adedb86f0c278124 100644 --- a/src/components/WatchFolder/checkmarkIcon.tsx +++ b/src/components/WatchFolder/checkmarkIcon.tsx @@ -5,7 +5,7 @@ export function CheckmarkIcon() { return ( theme.palette.secondary.main, }} /> diff --git a/src/components/WatchFolder/mappingEntry/entryHeading.tsx b/src/components/WatchFolder/mappingEntry/entryHeading.tsx index 12553f63e29f23cb59f37532e501a3069edaaf89..c0f5599969b9758ffa8fbb72ae6bfe043aa0709e 100644 --- a/src/components/WatchFolder/mappingEntry/entryHeading.tsx +++ b/src/components/WatchFolder/mappingEntry/entryHeading.tsx @@ -13,14 +13,8 @@ interface Iprops { export function EntryHeading({ mapping }: Iprops) { const appContext = useContext(AppContext); return ( - - - {mapping.rootFolderName} - + + {mapping.rootFolderName} {appContext.isFolderSyncRunning && watchFolderService.isMappingSyncing(mapping) && ( From 787ff7e8511e3d114bea1197996b138c283721da Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 16 Aug 2022 14:36:37 +0530 Subject: [PATCH 099/295] refactor lock util and types --- src/types/lock/index.ts | 4 ++++ src/utils/lock/index.ts | 14 ++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 src/types/lock/index.ts create mode 100644 src/utils/lock/index.ts diff --git a/src/types/lock/index.ts b/src/types/lock/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..bec0a736581f91ba4c532ccd964efbb8be845066 --- /dev/null +++ b/src/types/lock/index.ts @@ -0,0 +1,4 @@ +export interface Lock { + wait: Promise; + unlock(): void; +} diff --git a/src/utils/lock/index.ts b/src/utils/lock/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..23aaa939e8581132195947a543c452873580ca48 --- /dev/null +++ b/src/utils/lock/index.ts @@ -0,0 +1,14 @@ +import { Lock } from 'types/lock'; + +export function newLock(): Lock { + let resolver: () => void = null; + const wait = new Promise((resolve) => { + resolver = resolve; + }); + return { + wait, + unlock: () => { + resolver(); + }, + }; +} From d9894e654f4d749d62cf0ce7050fdbb10924fdba Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 17 Aug 2022 13:13:28 +0530 Subject: [PATCH 100/295] move HorizontalFlex to root container component --- src/components/Container.ts | 4 ++++ src/components/WatchFolder/mappingEntry/index.tsx | 4 ++-- src/components/WatchFolder/styledComponents.tsx | 5 +---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/components/Container.ts b/src/components/Container.ts index 76844f93b2bf9db227c19f9b25bcce2b9dc495cb..bcb7464ca67f244a1058f2e9f4aebc51a7027cc6 100644 --- a/src/components/Container.ts +++ b/src/components/Container.ts @@ -73,3 +73,7 @@ export const Overlay = styled(Box)` export const IconButtonWithBG = styled(IconButton)(({ theme }) => ({ backgroundColor: theme.palette.fill.dark, })); + +export const HorizontalFlex = styled(Box)({ + display: 'flex', +}); diff --git a/src/components/WatchFolder/mappingEntry/index.tsx b/src/components/WatchFolder/mappingEntry/index.tsx index 7e5f083144467826dbf0b03695f9a6a6ed0d3947..ef6b199defbbf46e6af12c001ee3ffefe25752a6 100644 --- a/src/components/WatchFolder/mappingEntry/index.tsx +++ b/src/components/WatchFolder/mappingEntry/index.tsx @@ -1,7 +1,7 @@ -import { EntryContainer, HorizontalFlex } from '../styledComponents'; +import { EntryContainer } from '../styledComponents'; import React from 'react'; import { Typography } from '@mui/material'; -import { SpaceBetweenFlex } from 'components/Container'; +import { HorizontalFlex, SpaceBetweenFlex } from 'components/Container'; import { WatchMapping } from 'types/watchFolder'; import { AppContext } from 'pages/_app'; import FolderOpenIcon from '@mui/icons-material/FolderOpen'; diff --git a/src/components/WatchFolder/styledComponents.tsx b/src/components/WatchFolder/styledComponents.tsx index ad3bdca7782546e99cbfe0acd3e2a2aeae80ea28..5b4427beb2e24af27c63ea6ad3e8f916f993a834 100644 --- a/src/components/WatchFolder/styledComponents.tsx +++ b/src/components/WatchFolder/styledComponents.tsx @@ -1,3 +1,4 @@ +import {} from './../Container'; import { Box } from '@mui/material'; import { styled } from '@mui/material/styles'; import VerticallyCentered from 'components/Container'; @@ -18,10 +19,6 @@ export const NoMappingsContainer = styled(VerticallyCentered)({ alignItems: 'flex-start', }); -export const HorizontalFlex = styled(Box)({ - display: 'flex', -}); - export const EntryContainer = styled(Box)({ marginLeft: '12px', marginRight: '6px', From 5d6ec4d755527f6b68f5244aebe943066809033a Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 17 Aug 2022 13:15:33 +0530 Subject: [PATCH 101/295] fix EntryHeading --- src/components/WatchFolder/mappingEntry/entryHeading.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/WatchFolder/mappingEntry/entryHeading.tsx b/src/components/WatchFolder/mappingEntry/entryHeading.tsx index c0f5599969b9758ffa8fbb72ae6bfe043aa0709e..d4386eb0b81e1f7c1bddd88977e9828e8b7da1b1 100644 --- a/src/components/WatchFolder/mappingEntry/entryHeading.tsx +++ b/src/components/WatchFolder/mappingEntry/entryHeading.tsx @@ -13,7 +13,7 @@ interface Iprops { export function EntryHeading({ mapping }: Iprops) { const appContext = useContext(AppContext); return ( - + {mapping.rootFolderName} {appContext.isFolderSyncRunning && watchFolderService.isMappingSyncing(mapping) && ( From 600ef6bd5187c4ed11ec3dc619d727f030ed9136 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 17 Aug 2022 13:25:06 +0530 Subject: [PATCH 102/295] refactor mapping entry options --- .../WatchFolder/mappingEntry/index.tsx | 6 +- .../WatchFolder/mappingEntryOptions.tsx | 64 +++++-------------- 2 files changed, 22 insertions(+), 48 deletions(-) diff --git a/src/components/WatchFolder/mappingEntry/index.tsx b/src/components/WatchFolder/mappingEntry/index.tsx index ef6b199defbbf46e6af12c001ee3ffefe25752a6..dd8d3a781c0fb3c671080f96260f4db5accb3b86 100644 --- a/src/components/WatchFolder/mappingEntry/index.tsx +++ b/src/components/WatchFolder/mappingEntry/index.tsx @@ -17,6 +17,10 @@ interface Iprops { export function MappingEntry({ mapping, handleRemoveMapping }: Iprops) { const appContext = React.useContext(AppContext); + const stopWatching = () => { + handleRemoveMapping(mapping); + }; + const confirmStopWatching = () => { appContext.setDialogMessage({ title: constants.STOP_WATCHING_FOLDER, @@ -26,7 +30,7 @@ export function MappingEntry({ mapping, handleRemoveMapping }: Iprops) { variant: 'primary', }, proceed: { - action: () => handleRemoveMapping(mapping), + action: stopWatching, text: constants.YES_STOP, variant: 'danger', }, diff --git a/src/components/WatchFolder/mappingEntryOptions.tsx b/src/components/WatchFolder/mappingEntryOptions.tsx index 10e9a7001aa5015bcb81b538f4d21be00001ec19..cd1b6af3c9e13e24a3d4aa9803b7989f7ce97e7f 100644 --- a/src/components/WatchFolder/mappingEntryOptions.tsx +++ b/src/components/WatchFolder/mappingEntryOptions.tsx @@ -1,55 +1,25 @@ -import { IconButton, Menu, MenuItem } from '@mui/material'; -import React, { useState } from 'react'; +import React from 'react'; import constants from 'utils/strings/constants'; import DoNotDisturbOutlinedIcon from '@mui/icons-material/DoNotDisturbOutlined'; import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; +import OverflowMenu from 'components/OverflowMenu/menu'; +import { OverflowMenuOption } from 'components/OverflowMenu/option'; -export default function MappingEntryOptions({ confirmStopWatching }) { - const [anchorEl, setAnchorEl] = useState(null); - const handleClick = (event: React.MouseEvent) => { - setAnchorEl(event.currentTarget); - }; - const handleClose = () => { - setAnchorEl(null); - }; +interface Iprops { + confirmStopWatching: () => void; +} - const open = Boolean(anchorEl); +export default function MappingEntryOptions({ confirmStopWatching }: Iprops) { return ( - <> - - - - - theme.palette.danger.main, - }}> - - - - {constants.STOP_WATCHING} - - - + }> + }> + {constants.STOP_WATCHING} + + ); } From c2424322680c771202e176e26b73a1bbe2637ba2 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 17 Aug 2022 13:28:56 +0530 Subject: [PATCH 103/295] remove syncProgressIcon and directly use Circular progress --- .../WatchFolder/mappingEntry/entryHeading.tsx | 7 +++---- .../WatchFolder/mappingEntry/syncProgressIcon.tsx | 13 ------------- 2 files changed, 3 insertions(+), 17 deletions(-) delete mode 100644 src/components/WatchFolder/mappingEntry/syncProgressIcon.tsx diff --git a/src/components/WatchFolder/mappingEntry/entryHeading.tsx b/src/components/WatchFolder/mappingEntry/entryHeading.tsx index d4386eb0b81e1f7c1bddd88977e9828e8b7da1b1..333e71baf672a8445453b25a9b440c457c09dc64 100644 --- a/src/components/WatchFolder/mappingEntry/entryHeading.tsx +++ b/src/components/WatchFolder/mappingEntry/entryHeading.tsx @@ -1,8 +1,7 @@ import React, { useContext } from 'react'; -import { Typography } from '@mui/material'; +import { CircularProgress, Typography } from '@mui/material'; import watchFolderService from 'services/watchFolder/watchFolderService'; import { AppContext } from 'pages/_app'; -import { SyncProgressIcon } from './syncProgressIcon'; import { FlexWrapper } from 'components/Container'; import { WatchMapping } from 'types/watchFolder'; @@ -13,11 +12,11 @@ interface Iprops { export function EntryHeading({ mapping }: Iprops) { const appContext = useContext(AppContext); return ( - + {mapping.rootFolderName} {appContext.isFolderSyncRunning && watchFolderService.isMappingSyncing(mapping) && ( - + )} ); diff --git a/src/components/WatchFolder/mappingEntry/syncProgressIcon.tsx b/src/components/WatchFolder/mappingEntry/syncProgressIcon.tsx deleted file mode 100644 index d221a7fb7b34c98eacda665850a5b42eec63d961..0000000000000000000000000000000000000000 --- a/src/components/WatchFolder/mappingEntry/syncProgressIcon.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import { CircularProgress } from '@mui/material'; - -export function SyncProgressIcon() { - return ( - - ); -} From 853fa414de3dda2d06a5e3800673f5b7b9dd2259 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 17 Aug 2022 13:30:17 +0530 Subject: [PATCH 104/295] rename function --- src/components/WatchFolder/mappingEntry/entryHeading.tsx | 2 +- src/services/watchFolder/watchFolderService.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/WatchFolder/mappingEntry/entryHeading.tsx b/src/components/WatchFolder/mappingEntry/entryHeading.tsx index 333e71baf672a8445453b25a9b440c457c09dc64..6d1912de7fd31f53fec8b87d7044d674195b357c 100644 --- a/src/components/WatchFolder/mappingEntry/entryHeading.tsx +++ b/src/components/WatchFolder/mappingEntry/entryHeading.tsx @@ -15,7 +15,7 @@ export function EntryHeading({ mapping }: Iprops) { {mapping.rootFolderName} {appContext.isFolderSyncRunning && - watchFolderService.isMappingSyncing(mapping) && ( + watchFolderService.isMappingSyncInProgress(mapping) && ( )} diff --git a/src/services/watchFolder/watchFolderService.ts b/src/services/watchFolder/watchFolderService.ts index 030f322eaee669564ba7533e8acf1fa23cbfcec2..c64296f4d97cc2afa14db9248ddae20973af9bfe 100644 --- a/src/services/watchFolder/watchFolderService.ts +++ b/src/services/watchFolder/watchFolderService.ts @@ -102,7 +102,7 @@ class watchFolderService { } } - isMappingSyncing(mapping: WatchMapping) { + isMappingSyncInProgress(mapping: WatchMapping) { return this.currentEvent?.folderPath === mapping.folderPath; } From abe5de2ec57a9432dacf0b891683e895933dea7b Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 17 Aug 2022 13:35:34 +0530 Subject: [PATCH 105/295] move mapping options inside mapping entry component directory --- .../WatchFolder/mappingEntry/index.tsx | 2 +- .../mappingEntry/mappingEntryOptions.tsx | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/components/WatchFolder/mappingEntry/mappingEntryOptions.tsx diff --git a/src/components/WatchFolder/mappingEntry/index.tsx b/src/components/WatchFolder/mappingEntry/index.tsx index dd8d3a781c0fb3c671080f96260f4db5accb3b86..5330c38286a550e4d9b723777b5dfdfdd8f760ed 100644 --- a/src/components/WatchFolder/mappingEntry/index.tsx +++ b/src/components/WatchFolder/mappingEntry/index.tsx @@ -6,7 +6,7 @@ import { WatchMapping } from 'types/watchFolder'; import { AppContext } from 'pages/_app'; import FolderOpenIcon from '@mui/icons-material/FolderOpen'; import constants from 'utils/strings/constants'; -import MappingEntryOptions from '../mappingEntryOptions'; +import MappingEntryOptions from './mappingEntryOptions'; import { EntryHeading } from './entryHeading'; interface Iprops { diff --git a/src/components/WatchFolder/mappingEntry/mappingEntryOptions.tsx b/src/components/WatchFolder/mappingEntry/mappingEntryOptions.tsx new file mode 100644 index 0000000000000000000000000000000000000000..cd1b6af3c9e13e24a3d4aa9803b7989f7ce97e7f --- /dev/null +++ b/src/components/WatchFolder/mappingEntry/mappingEntryOptions.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import constants from 'utils/strings/constants'; +import DoNotDisturbOutlinedIcon from '@mui/icons-material/DoNotDisturbOutlined'; +import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; +import OverflowMenu from 'components/OverflowMenu/menu'; +import { OverflowMenuOption } from 'components/OverflowMenu/option'; + +interface Iprops { + confirmStopWatching: () => void; +} + +export default function MappingEntryOptions({ confirmStopWatching }: Iprops) { + return ( + }> + }> + {constants.STOP_WATCHING} + + + ); +} From 93430df7cf9b6c4ec565810c08b1087c81dec296 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 17 Aug 2022 13:40:05 +0530 Subject: [PATCH 106/295] remove duplicate --- .../WatchFolder/mappingEntryOptions.tsx | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 src/components/WatchFolder/mappingEntryOptions.tsx diff --git a/src/components/WatchFolder/mappingEntryOptions.tsx b/src/components/WatchFolder/mappingEntryOptions.tsx deleted file mode 100644 index cd1b6af3c9e13e24a3d4aa9803b7989f7ce97e7f..0000000000000000000000000000000000000000 --- a/src/components/WatchFolder/mappingEntryOptions.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; -import constants from 'utils/strings/constants'; -import DoNotDisturbOutlinedIcon from '@mui/icons-material/DoNotDisturbOutlined'; -import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; -import OverflowMenu from 'components/OverflowMenu/menu'; -import { OverflowMenuOption } from 'components/OverflowMenu/option'; - -interface Iprops { - confirmStopWatching: () => void; -} - -export default function MappingEntryOptions({ confirmStopWatching }: Iprops) { - return ( - }> - }> - {constants.STOP_WATCHING} - - - ); -} From 6b353c6d7cd98a8a1511ab2efe70420df0cacf26 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 17 Aug 2022 13:49:24 +0530 Subject: [PATCH 107/295] refactor code --- src/components/WatchFolder/noMappingsContent.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/components/WatchFolder/noMappingsContent.tsx b/src/components/WatchFolder/noMappingsContent.tsx index 54eccf06bebb9aee55b77b0b40c99145cada305e..eda61870cabd914f622a6b62b9230d437b67ce5c 100644 --- a/src/components/WatchFolder/noMappingsContent.tsx +++ b/src/components/WatchFolder/noMappingsContent.tsx @@ -13,11 +13,15 @@ export function NoMappingsContent() { {constants.FOLDERS_AUTOMATICALLY_MONITORED} - - {constants.UPLOAD_NEW_FILES_TO_ENTE} + + + {constants.UPLOAD_NEW_FILES_TO_ENTE} - - {constants.REMOVE_DELETED_FILES_FROM_ENTE} + + + + {constants.REMOVE_DELETED_FILES_FROM_ENTE} + ); From ee686d430b7e25adf42508169d87dd1de1269d5e Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 17 Aug 2022 13:58:22 +0530 Subject: [PATCH 108/295] refactor code --- src/components/WatchFolder/index.tsx | 16 ++++------------ .../{mappingList.tsx => mappingList/index.tsx} | 9 ++++++--- .../noMappingsContent}/checkmarkIcon.tsx | 0 .../noMappingsContent}/noMappingsContent.tsx | 2 +- 4 files changed, 11 insertions(+), 16 deletions(-) rename src/components/WatchFolder/{mappingList.tsx => mappingList/index.tsx} (71%) rename src/components/WatchFolder/{ => mappingList/noMappingsContent}/checkmarkIcon.tsx (100%) rename src/components/WatchFolder/{ => mappingList/noMappingsContent}/noMappingsContent.tsx (94%) diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index 227672c1124046b9459b4dff1de2762b99f363f8..b16c1ecc1b9700dffe4d3b3f4806b58f173588fe 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -1,5 +1,4 @@ import { MappingList } from './mappingList'; -import { NoMappingsContent } from './noMappingsContent'; import React, { useContext, useEffect, useState } from 'react'; import { Button, Dialog, DialogContent, Stack } from '@mui/material'; import watchFolderService from 'services/watchFolder/watchFolderService'; @@ -98,17 +97,10 @@ export default function WatchFolder({ open, onClose }: Iprops) { - {mappings.length === 0 ? ( - - ) : ( - - )} - + + + + )} diff --git a/src/components/Upload/UploadButton.tsx b/src/components/Upload/UploadButton.tsx index 26454e286b029dc432511ffb834948012595ce1e..916b99e0594d4f4274569456055ec7c95a9550ac 100644 --- a/src/components/Upload/UploadButton.tsx +++ b/src/components/Upload/UploadButton.tsx @@ -3,6 +3,7 @@ import { IconButton, styled } from '@mui/material'; import FileUploadOutlinedIcon from '@mui/icons-material/FileUploadOutlined'; import { Button } from '@mui/material'; import constants from 'utils/strings/constants'; +import uploadManager from 'services/upload/uploadManager'; const Wrapper = styled('div')` display: flex; @@ -28,14 +29,23 @@ interface Iprops { } function UploadButton({ openUploader }: Iprops) { return ( - + - + + diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index 23e02179bf0d7277035cae66dea5a972bb2f044a..2645c76098614c65a32b0819923477dcb07f878e 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -564,9 +564,7 @@ export default function Gallery() { }; const openUploader = () => { - if (!uploadInProgress) { - setUploadTypeSelectorView(true); - } + setUploadTypeSelectorView(true); }; return ( diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index 686eaa4d8624e8e1d224cb175995287a34f4deaf..1a4f3ff59e6c6eab481021fdeadcf6c26bbac03e 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -545,6 +545,10 @@ class UploadManager { const updatedFile = await appendNewFilePath(decryptedFile, filePath); await updateFileMagicMetadata([updatedFile]); } + + public shouldAllowNewUpload = () => { + return !this.uploadInProgress || watchFolderService.isUploadRunning(); + }; } export default new UploadManager(); From 73c94d139ef672767a5cf13a64e4cfc4c2bde6e3 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 3 Sep 2022 17:40:33 +0530 Subject: [PATCH 196/295] convert console logs to addlogLine --- src/services/watchFolder/watchFolderEventHandlers.ts | 8 ++++---- src/services/watchFolder/watchFolderService.ts | 10 +++++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/services/watchFolder/watchFolderEventHandlers.ts b/src/services/watchFolder/watchFolderEventHandlers.ts index cf3c80dd1bfc7d600ab21a0f8469164119f51438..820acf3bc0dc721dca2223b76bbcc0630921c163 100644 --- a/src/services/watchFolder/watchFolderEventHandlers.ts +++ b/src/services/watchFolder/watchFolderEventHandlers.ts @@ -1,5 +1,6 @@ import { ElectronFile } from 'types/upload'; import { EventQueueItem } from 'types/watchFolder'; +import { addLogLine } from 'utils/logging'; import { logError } from 'utils/sentry'; import watchFolderService from './watchFolderService'; @@ -14,8 +15,6 @@ export async function diskFileAddedCallback(file: ElectronFile) { const { collectionName, folderPath } = collectionNameAndFolderPath; - console.log('added (upload) to event queue', collectionName, file); - const event: EventQueueItem = { type: 'upload', collectionName, @@ -23,6 +22,7 @@ export async function diskFileAddedCallback(file: ElectronFile) { files: [file], }; watchFolderService.pushEvent(event); + addLogLine(`added (upload) to event queue, ${JSON.stringify(event)}`); } catch (e) { logError(e, 'error while calling diskFileAddedCallback'); } @@ -39,8 +39,6 @@ export async function diskFileRemovedCallback(filePath: string) { const { collectionName, folderPath } = collectionNameAndFolderPath; - console.log('added (trash) to event queue', collectionName, filePath); - const event: EventQueueItem = { type: 'trash', collectionName, @@ -48,6 +46,7 @@ export async function diskFileRemovedCallback(filePath: string) { paths: [filePath], }; watchFolderService.pushEvent(event); + addLogLine(`added (trash) to event queue, ${JSON.stringify(event)}`); } catch (e) { logError(e, 'error while calling diskFileRemovedCallback'); } @@ -66,6 +65,7 @@ export async function diskFolderRemovedCallback(folderPath: string) { if (mappedFolderPath === folderPath) { watchFolderService.pushTrashedDir(folderPath); } + addLogLine(`added trashedDir, ${folderPath}`); } catch (e) { logError(e, 'error while calling diskFolderRemovedCallback'); } diff --git a/src/services/watchFolder/watchFolderService.ts b/src/services/watchFolder/watchFolderService.ts index 94b6d941a2c1b7b113973d476066888defbdba0c..255cd33537d6d1016ef3720c250335dd5930953b 100644 --- a/src/services/watchFolder/watchFolderService.ts +++ b/src/services/watchFolder/watchFolderService.ts @@ -19,6 +19,7 @@ import { import { getParentFolderName } from './utils'; import { UPLOAD_STRATEGY } from 'constants/upload'; import uploadManager from 'services/upload/uploadManager'; +import { addLogLine } from 'utils/logging'; class watchFolderService { private ElectronAPIs: ElectronAPIs; @@ -74,7 +75,7 @@ class watchFolderService { try { let mappings = this.getWatchMappings(); - console.log('mappings', mappings); + addLogLine(`mappings, ${mappings.map((m) => JSON.stringify(m))}`); if (!mappings?.length) { return; @@ -237,7 +238,10 @@ class watchFolderService { } private async runNextEvent() { - console.log('mappings', this.getWatchMappings()); + addLogLine( + `mappings, + ${this.getWatchMappings().map((m) => JSON.stringify(m))}` + ); if ( this.eventQueue.length === 0 || @@ -250,7 +254,7 @@ class watchFolderService { this.setIsEventRunning(true); const event = this.clubSameCollectionEvents(); this.currentEvent = event; - console.log('running event', event); + addLogLine(`running event', ${JSON.stringify(event)}`); if (event.type === 'upload') { this.processUploadEvent(); } else { From 9a12deebb02aa6cd3d082a6020ba21620200cd45 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 3 Sep 2022 17:42:01 +0530 Subject: [PATCH 197/295] don't update File Path --- src/services/upload/uploadManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index 1a4f3ff59e6c6eab481021fdeadcf6c26bbac03e..e33eef96c31da420b8961cb000b69f0d68992918 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -468,7 +468,6 @@ class UploadManager { ].includes(fileUploadResult) ) { this.updateExistingFiles(decryptedFile); - await this.updateFilePaths(decryptedFile, fileWithCollection); await this.watchFolderCallback( fileWithCollection, uploadedFile @@ -534,6 +533,7 @@ class UploadManager { } } + // not used private async updateFilePaths( decryptedFile: EnteFile, fileWithCollection: FileWithCollection From faac1e6f51eb5d83d2d50b7286dc0c4ee123e805 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 3 Sep 2022 18:01:44 +0530 Subject: [PATCH 198/295] moved watch folder to top of utility section --- src/components/Sidebar/UtilitySection.tsx | 7 +++---- src/utils/strings/englishConstants.tsx | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/Sidebar/UtilitySection.tsx b/src/components/Sidebar/UtilitySection.tsx index 53a90e4926630c2fec5a531e12858d3fd9adb591..cb55ca95db4a5b10f19bde600dc8bd2d53112193 100644 --- a/src/components/Sidebar/UtilitySection.tsx +++ b/src/components/Sidebar/UtilitySection.tsx @@ -62,6 +62,9 @@ export default function UtilitySection({ closeSidebar }) { return ( <> + + {constants.WATCH_FOLDERS} + {constants.RECOVERY_KEY} @@ -77,10 +80,6 @@ export default function UtilitySection({ closeSidebar }) { {constants.DEDUPLICATE_FILES} - - {constants.WATCH_FOLDERS} - - {/* {constants.COMPRESS_THUMBNAILS} */} diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx index d0e19568d51d1d09ecf5dcd80c2ced9776ee65eb..694024b4fe301302454b8b185f84082afef56cf2 100644 --- a/src/utils/strings/englishConstants.tsx +++ b/src/utils/strings/englishConstants.tsx @@ -739,7 +739,7 @@ const englishConstants = {

), - WATCH_FOLDERS: 'Watch Folders', + WATCH_FOLDERS: 'Watch folders', UPGRADE_NOW: 'Upgrade now', RENEW_NOW: 'Renew now', STORAGE: 'Storage', From 5628fbbb816670e64e2df96001b98553a2d2de70 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 3 Sep 2022 18:02:29 +0530 Subject: [PATCH 199/295] fix casing --- src/utils/strings/englishConstants.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx index 694024b4fe301302454b8b185f84082afef56cf2..a0fdaa22946e4083dc47818c75fdd5866bedcf7d 100644 --- a/src/utils/strings/englishConstants.tsx +++ b/src/utils/strings/englishConstants.tsx @@ -748,7 +748,7 @@ const englishConstants = { FAMILY: 'Family', FREE: 'free', OF: 'of', - WATCHED_FOLDERS: 'Watched Folders', + WATCHED_FOLDERS: 'Watched folders', NO_FOLDERS_ADDED: 'No folders added yet!', FOLDERS_AUTOMATICALLY_MONITORED: 'The folders you add here will monitored to automatically', From 1fb2d10ccec52d11f3c0fac7c43c74bbe221ed1c Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 3 Sep 2022 18:03:39 +0530 Subject: [PATCH 200/295] update max width --- src/components/WatchFolder/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index 89f94481199347f8e077b5fdee0f43311e8d3257..3a86f3b8ceeac7627d4e05adb64d4cb765d0e696 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -105,10 +105,9 @@ export default function WatchFolder({ open, onClose }: Iprops) { return ( <> + PaperProps={{ sx: { height: '450px', maxWidth: '432px' } }}> From 75e28d0a376c98253ed1ee701b6ab63eb4b52072 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 3 Sep 2022 18:05:11 +0530 Subject: [PATCH 201/295] made cancel button secondary --- src/components/WatchFolder/mappingEntry/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/WatchFolder/mappingEntry/index.tsx b/src/components/WatchFolder/mappingEntry/index.tsx index 5e8749aa00a28825753a86f373406c39cca62c7c..ec8e360b8d88ded2ba37953705c77347f2a1bb5a 100644 --- a/src/components/WatchFolder/mappingEntry/index.tsx +++ b/src/components/WatchFolder/mappingEntry/index.tsx @@ -29,7 +29,7 @@ export function MappingEntry({ mapping, handleRemoveMapping }: Iprops) { content: constants.STOP_WATCHING_DIALOG_MESSAGE, close: { text: constants.CANCEL, - variant: 'primary', + variant: 'secondary', }, proceed: { action: stopWatching, From bcb0fe7ed8d199bafc570c87d0f341668ee4a448 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 3 Sep 2022 18:26:05 +0530 Subject: [PATCH 202/295] make ui changes --- .../noMappingsContent/checkmarkIcon.tsx | 5 +++- .../noMappingsContent/noMappingsContent.tsx | 29 ++++++++++--------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/components/WatchFolder/mappingList/noMappingsContent/checkmarkIcon.tsx b/src/components/WatchFolder/mappingList/noMappingsContent/checkmarkIcon.tsx index 10b4f0459262352012896e55adedb86f0c278124..6317363290fabca6f72305f6ffb5343acabfa0cf 100644 --- a/src/components/WatchFolder/mappingList/noMappingsContent/checkmarkIcon.tsx +++ b/src/components/WatchFolder/mappingList/noMappingsContent/checkmarkIcon.tsx @@ -4,8 +4,11 @@ import CheckIcon from '@mui/icons-material/Check'; export function CheckmarkIcon() { return ( theme.palette.secondary.main, }} /> diff --git a/src/components/WatchFolder/mappingList/noMappingsContent/noMappingsContent.tsx b/src/components/WatchFolder/mappingList/noMappingsContent/noMappingsContent.tsx index 85a4a8749756b9d5e64c27c7a390def6cb186e84..335057465502e54c61422c8a238eda9df04692e2 100644 --- a/src/components/WatchFolder/mappingList/noMappingsContent/noMappingsContent.tsx +++ b/src/components/WatchFolder/mappingList/noMappingsContent/noMappingsContent.tsx @@ -1,28 +1,31 @@ import { Typography } from '@mui/material'; -import { FlexWrapper } from 'components/Container'; import React from 'react'; import constants from 'utils/strings/constants'; -import { CheckmarkIcon } from './checkmarkIcon'; import { NoMappingsContainer } from '../../styledComponents'; +import { FlexWrapper } from 'components/Container'; +import { CheckmarkIcon } from './checkmarkIcon'; + export function NoMappingsContent() { return ( - + {constants.NO_FOLDERS_ADDED} - + {constants.FOLDERS_AUTOMATICALLY_MONITORED} - - - {constants.UPLOAD_NEW_FILES_TO_ENTE} - - - - + + + + {constants.UPLOAD_NEW_FILES_TO_ENTE} + + + + + {constants.REMOVE_DELETED_FILES_FROM_ENTE} - - +
+ ); } From ea2d142d60b2a61c7a337e9d87e4c258448bb4ac Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 3 Sep 2022 18:47:47 +0530 Subject: [PATCH 203/295] fix sizing and layout --- src/components/WatchFolder/index.tsx | 2 +- src/components/WatchFolder/styledComponents.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/WatchFolder/index.tsx b/src/components/WatchFolder/index.tsx index 3a86f3b8ceeac7627d4e05adb64d4cb765d0e696..ff5ca59aa62f42963469f7cd2b626885d8419356 100644 --- a/src/components/WatchFolder/index.tsx +++ b/src/components/WatchFolder/index.tsx @@ -107,7 +107,7 @@ export default function WatchFolder({ open, onClose }: Iprops) { + PaperProps={{ sx: { height: '448px', maxWidth: '414px' } }}> diff --git a/src/components/WatchFolder/styledComponents.tsx b/src/components/WatchFolder/styledComponents.tsx index 5b4427beb2e24af27c63ea6ad3e8f916f993a834..3e6d595c1416cc1dbbb393bca79a275cc821d149 100644 --- a/src/components/WatchFolder/styledComponents.tsx +++ b/src/components/WatchFolder/styledComponents.tsx @@ -17,6 +17,7 @@ export const MappingsContainer = styled(Box)(({ theme }) => ({ export const NoMappingsContainer = styled(VerticallyCentered)({ textAlign: 'left', alignItems: 'flex-start', + marginBottom: '32px', }); export const EntryContainer = styled(Box)({ From 1e433594142b9cf1642709de39f61187195c9633 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 3 Sep 2022 18:54:41 +0530 Subject: [PATCH 204/295] make overflow menu background to over paper --- .../WatchFolder/mappingEntry/mappingEntryOptions.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/WatchFolder/mappingEntry/mappingEntryOptions.tsx b/src/components/WatchFolder/mappingEntry/mappingEntryOptions.tsx index cd1b6af3c9e13e24a3d4aa9803b7989f7ce97e7f..8189a4c3d01b937f52dd003736d43c8ba47c27f4 100644 --- a/src/components/WatchFolder/mappingEntry/mappingEntryOptions.tsx +++ b/src/components/WatchFolder/mappingEntry/mappingEntryOptions.tsx @@ -12,6 +12,12 @@ interface Iprops { export default function MappingEntryOptions({ confirmStopWatching }: Iprops) { return ( + theme.palette.background.overPaper, + }, + }} ariaControls={'watch-mapping-option'} triggerButtonIcon={}> Date: Sat, 3 Sep 2022 19:30:07 +0530 Subject: [PATCH 205/295] fix already upload file not getting added as synced file --- src/services/upload/uploadManager.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index e33eef96c31da420b8961cb000b69f0d68992918..6ebd4a319d49bc1c1abc9ca89e30d037183fae80 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -468,6 +468,15 @@ class UploadManager { ].includes(fileUploadResult) ) { this.updateExistingFiles(decryptedFile); + } + if ( + [ + UPLOAD_RESULT.ADDED_SYMLINK, + UPLOAD_RESULT.UPLOADED, + UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL, + UPLOAD_RESULT.ALREADY_UPLOADED, + ].includes(fileUploadResult) + ) { await this.watchFolderCallback( fileWithCollection, uploadedFile From 88d265409572031dacb7ad1530595844c7e3004a Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 3 Sep 2022 19:30:44 +0530 Subject: [PATCH 206/295] add local log --- .../watchFolder/watchFolderService.ts | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/services/watchFolder/watchFolderService.ts b/src/services/watchFolder/watchFolderService.ts index 255cd33537d6d1016ef3720c250335dd5930953b..17f97bd39ae02778b03a406af17551d2eda405ba 100644 --- a/src/services/watchFolder/watchFolderService.ts +++ b/src/services/watchFolder/watchFolderService.ts @@ -19,7 +19,7 @@ import { import { getParentFolderName } from './utils'; import { UPLOAD_STRATEGY } from 'constants/upload'; import uploadManager from 'services/upload/uploadManager'; -import { addLogLine } from 'utils/logging'; +import { addLocalLog, addLogLine } from 'utils/logging'; class watchFolderService { private ElectronAPIs: ElectronAPIs; @@ -276,6 +276,7 @@ class watchFolderService { } async onFileUpload(fileWithCollection: FileWithCollection, file: EnteFile) { + addLocalLog(() => `onFileUpload called`); if (!this.isUploadRunning) { return; } @@ -302,10 +303,17 @@ class watchFolderService { ) { if (this.allElectronAPIsExist) { try { + addLocalLog( + () => + `allFileUploadsDone,${JSON.stringify( + filesWithCollection + )} ${JSON.stringify(collections)}` + ); const collection = collections.find( (collection) => collection.id === filesWithCollection[0].collectionID ); + addLocalLog(() => `got collection ${!!collection}`); if ( !this.isEventRunning || this.currentEvent.collectionName !== collection?.name @@ -319,6 +327,10 @@ class watchFolderService { this.handleUploadedFile(fileWithCollection, uploadedFiles); } + addLocalLog( + () => `uploadedFiles ${JSON.stringify(uploadedFiles)}` + ); + if (uploadedFiles.length > 0) { const mappings = this.getWatchMappings(); const mapping = mappings.find( @@ -363,15 +375,22 @@ class watchFolderService { this.pathToIDMap.has(imagePath) && this.pathToIDMap.has(videoPath) ) { - uploadedFiles.push({ + const imageFile = { path: imagePath, id: this.pathToIDMap.get(imagePath), - }); - uploadedFiles.push({ + }; + const videoFile = { path: videoPath, id: this.pathToIDMap.get(videoPath), - }); - + }; + uploadedFiles.push(imageFile); + uploadedFiles.push(videoFile); + addLocalLog( + () => + `added image ${JSON.stringify( + imageFile + )} and video file ${JSON.stringify(videoFile)}` + ); this.pathToIDMap.delete(imagePath); this.pathToIDMap.delete(videoPath); } @@ -379,11 +398,12 @@ class watchFolderService { const filePath = (fileWithCollection.file as ElectronFile).path; if (this.pathToIDMap.has(filePath)) { - uploadedFiles.push({ + const file = { path: filePath, id: this.pathToIDMap.get(filePath), - }); - + }; + uploadedFiles.push(file); + addLocalLog(() => `added file ${JSON.stringify(file)} `); this.pathToIDMap.delete(filePath); } } @@ -480,7 +500,7 @@ class watchFolderService { ); if (!mapping) { - return null; + throw Error(`no mapping found for ${filePath}`); } return { From f8b0706d81c886771b05754abeb9217a0593e7cf Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 3 Sep 2022 20:38:25 +0530 Subject: [PATCH 207/295] add files that can't be uploaded to ignored files --- src/services/upload/uploadManager.ts | 20 +- .../watchFolder/watchFolderService.ts | 242 ++++++++++++------ src/types/electron/index.ts | 8 +- src/types/watchFolder/index.ts | 11 +- 4 files changed, 177 insertions(+), 104 deletions(-) diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index 6ebd4a319d49bc1c1abc9ca89e30d037183fae80..e4c50c6d4dd4f581320c9a7f99ca275113906475 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -469,19 +469,11 @@ class UploadManager { ) { this.updateExistingFiles(decryptedFile); } - if ( - [ - UPLOAD_RESULT.ADDED_SYMLINK, - UPLOAD_RESULT.UPLOADED, - UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL, - UPLOAD_RESULT.ALREADY_UPLOADED, - ].includes(fileUploadResult) - ) { - await this.watchFolderCallback( - fileWithCollection, - uploadedFile - ); - } + await this.watchFolderCallback( + fileUploadResult, + fileWithCollection, + uploadedFile + ); return fileUploadResult; } catch (e) { logError(e, 'failed to do post file upload action'); @@ -494,11 +486,13 @@ class UploadManager { } private async watchFolderCallback( + fileUploadResult: UPLOAD_RESULT, fileWithCollection: FileWithCollection, uploadedFile: EnteFile ) { if (isElectron()) { await watchFolderService.onFileUpload( + fileUploadResult, fileWithCollection, uploadedFile ); diff --git a/src/services/watchFolder/watchFolderService.ts b/src/services/watchFolder/watchFolderService.ts index 17f97bd39ae02778b03a406af17551d2eda405ba..2d9ac7ae19c534c3cd4812a7c9c1d99fa21f8c6e 100644 --- a/src/services/watchFolder/watchFolderService.ts +++ b/src/services/watchFolder/watchFolderService.ts @@ -17,7 +17,7 @@ import { diskFolderRemovedCallback, } from './watchFolderEventHandlers'; import { getParentFolderName } from './utils'; -import { UPLOAD_STRATEGY } from 'constants/upload'; +import { UPLOAD_RESULT, UPLOAD_STRATEGY } from 'constants/upload'; import uploadManager from 'services/upload/uploadManager'; import { addLocalLog, addLogLine } from 'utils/logging'; @@ -26,10 +26,12 @@ class watchFolderService { private allElectronAPIsExist: boolean = false; private eventQueue: EventQueueItem[] = []; private currentEvent: EventQueueItem; + private currentlySyncedMapping: WatchMapping; private trashingDirQueue: string[] = []; private isEventRunning: boolean = false; private uploadRunning: boolean = false; - private pathToIDMap = new Map(); + private filePathToUploadedFileIDMap = new Map(); + private unUploadableFilePaths = new Set(); private isPaused = false; private setElectronFiles: (files: ElectronFile[]) => void; private setCollectionName: (collectionName: string) => void; @@ -108,8 +110,10 @@ class watchFolderService { filesOnDisk: ElectronFile[] ) { const filesToUpload = filesOnDisk.filter((electronFile) => { - return !mapping.files.find( - (file) => file.path === electronFile.path + return ( + !mapping.syncedFiles.find( + (file) => file.path === electronFile.path + ) && !mapping.ignoredFiles.includes(electronFile.path) ); }); @@ -133,7 +137,7 @@ class watchFolderService { mapping: WatchMapping, filesOnDisk: ElectronFile[] ) { - const filesToRemove = mapping.files.filter((file) => { + const filesToRemove = mapping.syncedFiles.filter((file) => { return !filesOnDisk.find( (electronFile) => electronFile.path === file.path ); @@ -238,27 +242,40 @@ class watchFolderService { } private async runNextEvent() { - addLogLine( - `mappings, + try { + addLogLine( + `mappings, ${this.getWatchMappings().map((m) => JSON.stringify(m))}` - ); + ); - if ( - this.eventQueue.length === 0 || - this.isEventRunning || - this.isPaused - ) { - return; - } + if ( + this.eventQueue.length === 0 || + this.isEventRunning || + this.isPaused + ) { + return; + } - this.setIsEventRunning(true); - const event = this.clubSameCollectionEvents(); - this.currentEvent = event; - addLogLine(`running event', ${JSON.stringify(event)}`); - if (event.type === 'upload') { - this.processUploadEvent(); - } else { - await this.processTrashEvent(); + this.setIsEventRunning(true); + const event = this.clubSameCollectionEvents(); + this.currentEvent = event; + const mappings = this.getWatchMappings(); + const mapping = mappings.find( + (mapping) => mapping.folderPath === this.currentEvent.folderPath + ); + if (!mapping) { + throw Error('no Mapping found for event'); + } + this.currentlySyncedMapping = mapping; + addLogLine(`running event', ${JSON.stringify(event)}`); + if (event.type === 'upload') { + this.processUploadEvent(); + } else { + await this.processTrashEvent(); + } + } catch (e) { + logError(e, 'runNextEvent failed'); + } finally { this.setIsEventRunning(false); this.runNextEvent(); } @@ -275,25 +292,59 @@ class watchFolderService { } } - async onFileUpload(fileWithCollection: FileWithCollection, file: EnteFile) { + async onFileUpload( + fileUploadResult: UPLOAD_RESULT, + fileWithCollection: FileWithCollection, + file: EnteFile + ) { addLocalLog(() => `onFileUpload called`); if (!this.isUploadRunning) { return; } - if (fileWithCollection.isLivePhoto) { - this.pathToIDMap.set( - (fileWithCollection.livePhotoAssets.image as ElectronFile).path, - file.id - ); - this.pathToIDMap.set( - (fileWithCollection.livePhotoAssets.video as ElectronFile).path, - file.id - ); - } else { - this.pathToIDMap.set( - (fileWithCollection.file as ElectronFile).path, - file.id - ); + if ( + [ + UPLOAD_RESULT.ADDED_SYMLINK, + UPLOAD_RESULT.UPLOADED, + UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL, + UPLOAD_RESULT.ALREADY_UPLOADED, + ].includes(fileUploadResult) + ) { + if (fileWithCollection.isLivePhoto) { + this.filePathToUploadedFileIDMap.set( + (fileWithCollection.livePhotoAssets.image as ElectronFile) + .path, + file.id + ); + this.filePathToUploadedFileIDMap.set( + (fileWithCollection.livePhotoAssets.video as ElectronFile) + .path, + file.id + ); + } else { + this.filePathToUploadedFileIDMap.set( + (fileWithCollection.file as ElectronFile).path, + file.id + ); + } + } else if ( + [UPLOAD_RESULT.UNSUPPORTED, UPLOAD_RESULT.TOO_LARGE].includes( + fileUploadResult + ) + ) { + if (fileWithCollection.isLivePhoto) { + this.unUploadableFilePaths.add( + (fileWithCollection.livePhotoAssets.image as ElectronFile) + .path + ); + this.unUploadableFilePaths.add( + (fileWithCollection.livePhotoAssets.video as ElectronFile) + .path + ); + } else { + this.unUploadableFilePaths.add( + (fileWithCollection.file as ElectronFile).path + ); + } } } @@ -321,29 +372,41 @@ class watchFolderService { return; } - const uploadedFiles: WatchMapping['files'] = []; + const syncedFiles: WatchMapping['syncedFiles'] = []; + const ignoredFiles: WatchMapping['ignoredFiles'] = []; for (const fileWithCollection of filesWithCollection) { - this.handleUploadedFile(fileWithCollection, uploadedFiles); + this.handleUploadedFile( + fileWithCollection, + syncedFiles, + ignoredFiles + ); } + addLocalLog(() => `syncedFiles ${JSON.stringify(syncedFiles)}`); addLocalLog( - () => `uploadedFiles ${JSON.stringify(uploadedFiles)}` + () => `ignoredFiles ${JSON.stringify(ignoredFiles)}` ); - if (uploadedFiles.length > 0) { - const mappings = this.getWatchMappings(); - const mapping = mappings.find( - (mapping) => - mapping.folderPath === this.currentEvent.folderPath + if (syncedFiles.length > 0) { + this.currentlySyncedMapping.syncedFiles = [ + ...this.currentlySyncedMapping.syncedFiles, + ...syncedFiles, + ]; + this.ElectronAPIs.updateWatchMappingSyncedFiles( + this.currentlySyncedMapping.folderPath, + this.currentlySyncedMapping.syncedFiles + ); + } + if (ignoredFiles.length > 0) { + this.currentlySyncedMapping.ignoredFiles = [ + ...this.currentlySyncedMapping.ignoredFiles, + ...ignoredFiles, + ]; + this.ElectronAPIs.updateWatchMappingIgnoredFiles( + this.currentlySyncedMapping.folderPath, + this.currentlySyncedMapping.ignoredFiles ); - if (mapping) { - mapping.files = [...mapping.files, ...uploadedFiles]; - this.ElectronAPIs.updateWatchMappingFiles( - mapping.folderPath, - mapping.files - ); - } } this.runPostUploadsAction(); @@ -361,7 +424,8 @@ class watchFolderService { private handleUploadedFile( fileWithCollection: FileWithCollection, - uploadedFiles: { path: string; id: number }[] + syncedFiles: { path: string; id: number }[], + ignoredFiles: string[] ) { if (fileWithCollection.isLivePhoto) { const imagePath = ( @@ -372,40 +436,55 @@ class watchFolderService { ).path; if ( - this.pathToIDMap.has(imagePath) && - this.pathToIDMap.has(videoPath) + this.filePathToUploadedFileIDMap.has(imagePath) && + this.filePathToUploadedFileIDMap.has(videoPath) ) { const imageFile = { path: imagePath, - id: this.pathToIDMap.get(imagePath), + id: this.filePathToUploadedFileIDMap.get(imagePath), }; const videoFile = { path: videoPath, - id: this.pathToIDMap.get(videoPath), + id: this.filePathToUploadedFileIDMap.get(videoPath), }; - uploadedFiles.push(imageFile); - uploadedFiles.push(videoFile); + syncedFiles.push(imageFile); + syncedFiles.push(videoFile); addLocalLog( () => `added image ${JSON.stringify( imageFile - )} and video file ${JSON.stringify(videoFile)}` + )} and video file ${JSON.stringify( + videoFile + )} to uploadedFiles` + ); + } else if ( + this.unUploadableFilePaths.has(imagePath) && + this.unUploadableFilePaths.has(videoPath) + ) { + ignoredFiles.push(imagePath); + ignoredFiles.push(videoPath); + addLocalLog( + () => + `added image ${imagePath} and video file ${videoPath} to rejectedFiles` ); - this.pathToIDMap.delete(imagePath); - this.pathToIDMap.delete(videoPath); } + this.filePathToUploadedFileIDMap.delete(imagePath); + this.filePathToUploadedFileIDMap.delete(videoPath); } else { const filePath = (fileWithCollection.file as ElectronFile).path; - if (this.pathToIDMap.has(filePath)) { + if (this.filePathToUploadedFileIDMap.has(filePath)) { const file = { path: filePath, - id: this.pathToIDMap.get(filePath), + id: this.filePathToUploadedFileIDMap.get(filePath), }; - uploadedFiles.push(file); + syncedFiles.push(file); addLocalLog(() => `added file ${JSON.stringify(file)} `); - this.pathToIDMap.delete(filePath); + } else if (this.unUploadableFilePaths.has(filePath)) { + ignoredFiles.push(filePath); + addLocalLog(() => `added file ${filePath} to rejectedFiles`); } + this.filePathToUploadedFileIDMap.delete(filePath); } } @@ -415,29 +494,22 @@ class watchFolderService { return; } - const { collectionName, folderPath, paths } = this.currentEvent; + const { collectionName, paths } = this.currentEvent; const filePathsToRemove = new Set(paths); - const mappings = this.getWatchMappings(); - const mappingIdx = mappings.findIndex( - (mapping) => mapping.folderPath === folderPath - ); - if (mappingIdx === -1) { - return; - } - - const files = mappings[mappingIdx].files.filter((file) => - filePathsToRemove.has(file.path) + const files = this.currentlySyncedMapping.syncedFiles.filter( + (file) => filePathsToRemove.has(file.path) ); await this.trashByIDs(files, collectionName); - mappings[mappingIdx].files = mappings[mappingIdx].files.filter( - (file) => !filePathsToRemove.has(file.path) - ); - this.ElectronAPIs.updateWatchMappingFiles( - mappings[mappingIdx].folderPath, - mappings[mappingIdx].files + this.currentlySyncedMapping.syncedFiles = + this.currentlySyncedMapping.syncedFiles.filter( + (file) => !filePathsToRemove.has(file.path) + ); + this.ElectronAPIs.updateWatchMappingSyncedFiles( + this.currentlySyncedMapping.folderPath, + this.currentlySyncedMapping.syncedFiles ); } catch (e) { logError(e, 'error while running next trash'); @@ -445,7 +517,7 @@ class watchFolderService { } private async trashByIDs( - toTrashFiles: WatchMapping['files'], + toTrashFiles: WatchMapping['syncedFiles'], collectionName: string ) { try { diff --git a/src/types/electron/index.ts b/src/types/electron/index.ts index 59615347bf6ebe1aa753e9147ba637eb7cd788ce..3bb4f59bc26d949b95889f015defbba1b6e06dca 100644 --- a/src/types/electron/index.ts +++ b/src/types/electron/index.ts @@ -37,9 +37,13 @@ export interface ElectronAPIs { setToUploadCollection: (collectionName: string) => void; getDirFiles: (dirPath: string) => Promise; getWatchMappings: () => WatchMapping[]; - updateWatchMappingFiles: ( + updateWatchMappingSyncedFiles: ( folderPath: string, - files: WatchMapping['files'] + files: WatchMapping['syncedFiles'] + ) => void; + updateWatchMappingIgnoredFiles: ( + folderPath: string, + files: WatchMapping['ignoredFiles'] ) => void; addWatchMapping: ( collectionName: string, diff --git a/src/types/watchFolder/index.ts b/src/types/watchFolder/index.ts index 97fa96dceed2fb051ef2ba20b02264f9bb1a5f2b..d191d735860c474b3d48077b02a38ce2bc0c8586 100644 --- a/src/types/watchFolder/index.ts +++ b/src/types/watchFolder/index.ts @@ -1,14 +1,17 @@ import { UPLOAD_STRATEGY } from 'constants/upload'; import { ElectronFile } from 'types/upload'; +interface WatchMappingSyncedFile { + path: string; + id: number; +} + export interface WatchMapping { rootFolderName: string; folderPath: string; uploadStrategy: UPLOAD_STRATEGY; - files: { - path: string; - id: number; - }[]; + syncedFiles: WatchMappingSyncedFile[]; + ignoredFiles: string[]; } export interface EventQueueItem { From 513c7cf167dd23c9ba8ef74e8be7583175218638 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 3 Sep 2022 21:01:05 +0530 Subject: [PATCH 208/295] fix uploadDone not runnign --- src/services/watchFolder/watchFolderService.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/services/watchFolder/watchFolderService.ts b/src/services/watchFolder/watchFolderService.ts index 2d9ac7ae19c534c3cd4812a7c9c1d99fa21f8c6e..df4c8d29427d7854314364079485560e4e64bcea 100644 --- a/src/services/watchFolder/watchFolderService.ts +++ b/src/services/watchFolder/watchFolderService.ts @@ -272,12 +272,11 @@ class watchFolderService { this.processUploadEvent(); } else { await this.processTrashEvent(); + this.setIsEventRunning(false); + this.runNextEvent(); } } catch (e) { logError(e, 'runNextEvent failed'); - } finally { - this.setIsEventRunning(false); - this.runNextEvent(); } } @@ -365,6 +364,10 @@ class watchFolderService { collection.id === filesWithCollection[0].collectionID ); addLocalLog(() => `got collection ${!!collection}`); + addLocalLog( + () => + `${this.isEventRunning} ${this.currentEvent.collectionName} ${collection?.name}` + ); if ( !this.isEventRunning || this.currentEvent.collectionName !== collection?.name From 8aab1cbd0466895313e5fc3c8d5130b27aac47fd Mon Sep 17 00:00:00 2001 From: Abhinav Date: Mon, 5 Sep 2022 19:29:03 +0530 Subject: [PATCH 209/295] fix waitAndRun and better name --- src/components/Upload/Uploader.tsx | 16 +++++++++------- src/pages/gallery/index.tsx | 6 +++--- src/utils/common/index.ts | 7 +++++-- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/components/Upload/Uploader.tsx b/src/components/Upload/Uploader.tsx index 7b16ff456cecfe3c3ca2d500f6b050fec479ae64..b0739b84f8288b6092ce721dd4f0f039556dcc91 100644 --- a/src/components/Upload/Uploader.tsx +++ b/src/components/Upload/Uploader.tsx @@ -57,7 +57,7 @@ interface Props { setCollectionSelectorAttributes: SetCollectionSelectorAttributes; setCollectionNamerAttributes: SetCollectionNamerAttributes; setLoading: SetLoading; - setUploadInProgress: (value: boolean) => void; + setShouldDisableDropzone: (value: boolean) => void; showCollectionSelector: () => void; setFiles: SetFiles; setCollections: SetCollections; @@ -100,7 +100,7 @@ export default function Uploader(props: Props) { // This is set when the user choses a type to upload from the upload type selector dialog const pickedUploadType = useRef(null); const zipPaths = useRef(null); - const previousUploadPromise = useRef>(null); + const currentUploadPromise = useRef>(null); const [electronFiles, setElectronFiles] = useState(null); const [webFiles, setWebFiles] = useState([]); @@ -327,9 +327,11 @@ export default function Uploader(props: Props) { filesWithCollectionToUploadIn: FileWithCollection[], collections: Collection[] ) => { - const currentPromise = previousUploadPromise.current; - previousUploadPromise.current = waitAndRun(currentPromise, () => - uploadFiles(filesWithCollectionToUploadIn, collections) + const currentPromise = currentUploadPromise.current; + currentUploadPromise.current = waitAndRun( + currentPromise, + async () => + await uploadFiles(filesWithCollectionToUploadIn, collections) ); }; @@ -338,12 +340,12 @@ export default function Uploader(props: Props) { props.closeUploadTypeSelector(); uploadManager.prepareForNewUpload(); setUploadProgressView(true); - props.setUploadInProgress(true); + props.setShouldDisableDropzone(!uploadManager.shouldAllowNewUpload()); await props.syncWithRemote(true, true); }; function postUploadAction() { - props.setUploadInProgress(false); + props.setShouldDisableDropzone(false); props.syncWithRemote(); } diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index 2645c76098614c65a32b0819923477dcb07f878e..44f698c287d560ee16cd8318b5d397b62f759d63 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -149,7 +149,7 @@ export default function Gallery() { useState(null); const [collectionNamerView, setCollectionNamerView] = useState(false); const [search, setSearch] = useState(null); - const [uploadInProgress, setUploadInProgress] = useState(false); + const [shouldDisableDropzone, setShouldDisableDropzone] = useState(false); const { getRootProps: getDragAndDropRootProps, @@ -158,7 +158,7 @@ export default function Gallery() { } = useDropzone({ noClick: true, noKeyboard: true, - disabled: uploadInProgress, + disabled: shouldDisableDropzone, }); const { selectedFiles: webFileSelectorFiles, @@ -666,7 +666,7 @@ export default function Gallery() { )} setLoading={setBlockingLoad} setCollectionNamerAttributes={setCollectionNamerAttributes} - setUploadInProgress={setUploadInProgress} + setShouldDisableDropzone={setShouldDisableDropzone} setFiles={setFiles} setCollections={setCollections} isFirstUpload={hasNonEmptyCollections(collectionSummaries)} diff --git a/src/utils/common/index.ts b/src/utils/common/index.ts index 0e71519e6404c1580484174830d11dc2bc0aa2da..b8eb8fef3fc43b66497f198bd4a652997f7f6d7a 100644 --- a/src/utils/common/index.ts +++ b/src/utils/common/index.ts @@ -93,11 +93,14 @@ export function openLink(href: string, newTab?: boolean) { a.click(); } -export async function waitAndRun(waitPromise: Promise, task: () => void) { +export async function waitAndRun( + waitPromise: Promise, + task: () => Promise +) { if (waitPromise && isPromise(waitPromise)) { await waitPromise; } - task(); + await task(); } function isPromise(p: any) { From aafc3af100919849fe51ea325eea12da9a95bc63 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Mon, 5 Sep 2022 21:14:08 +0530 Subject: [PATCH 210/295] add getAccountDeleteChallenge api --- src/services/userService.ts | 19 +++++++++++++++++++ src/types/user/index.ts | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/src/services/userService.ts b/src/services/userService.ts index 832455d1dd7c2316546385e604ec8810895dcce7..56a31c4c9f0ed1fc40f1efaee5a05a7d1b80d8df 100644 --- a/src/services/userService.ts +++ b/src/services/userService.ts @@ -16,6 +16,7 @@ import { TwoFactorVerificationResponse, TwoFactorRecoveryResponse, UserDetails, + DeleteChallengeResponse, } from 'types/user'; import { getLocalFamilyData, isPartOfFamily } from 'utils/billing'; import { ServerErrorCodes } from 'utils/error'; @@ -324,3 +325,21 @@ export const getFamilyPortalRedirectURL = async () => { throw e; } }; + +export const getAccountDeleteChallenge = async () => { + try { + const token = getToken(); + + const resp = await HTTPService.get( + `${ENDPOINT}/users/delete-challenge`, + null, + { + 'X-Auth-Token': token, + } + ); + return resp.data as DeleteChallengeResponse; + } catch (e) { + logError(e, 'failed to get roadmap url'); + throw e; + } +}; diff --git a/src/types/user/index.ts b/src/types/user/index.ts index 243add01aceec1fcae15719dea57a58e28bbcf3a..c47dca3fbcfcc4acbc9f5cec73cd1eaa4b00cc7e 100644 --- a/src/types/user/index.ts +++ b/src/types/user/index.ts @@ -87,3 +87,8 @@ export interface UserDetails { subscription: Subscription; familyData?: FamilyData; } + +export interface DeleteChallengeResponse { + allowDelete: boolean; + encryptedChallenge: string; +} From dbfffdeb6ccb8cf0b4d12ca8475fbacc31c677f6 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Mon, 5 Sep 2022 21:16:51 +0530 Subject: [PATCH 211/295] refactored credential into verify master password form --- src/components/VerifyMasterPasswordForm.tsx | 80 ++++++++++++++++++ src/pages/credentials/index.tsx | 92 +++++---------------- 2 files changed, 102 insertions(+), 70 deletions(-) create mode 100644 src/components/VerifyMasterPasswordForm.tsx diff --git a/src/components/VerifyMasterPasswordForm.tsx b/src/components/VerifyMasterPasswordForm.tsx new file mode 100644 index 0000000000000000000000000000000000000000..08674565ad7d5a2ad4354b4e3e1710e49c712d34 --- /dev/null +++ b/src/components/VerifyMasterPasswordForm.tsx @@ -0,0 +1,80 @@ +import React from 'react'; + +import constants from 'utils/strings/constants'; +import CryptoWorker from 'utils/crypto'; +import SingleInputForm, { + SingleInputFormProps, +} from 'components/SingleInputForm'; +import { logError } from 'utils/sentry'; +import { CustomError } from 'utils/error'; + +import { Input } from '@mui/material'; + +export default function VerifyMasterPasswordForm({ + user, + keyAttributes, + callback, +}) { + const verifyPassphrase: SingleInputFormProps['callback'] = async ( + passphrase, + setFieldError + ) => { + try { + const cryptoWorker = await new CryptoWorker(); + let kek: string = null; + try { + kek = await cryptoWorker.deriveKey( + passphrase, + keyAttributes.kekSalt, + keyAttributes.opsLimit, + keyAttributes.memLimit + ); + } catch (e) { + logError(e, 'failed to derive key'); + throw Error(CustomError.WEAK_DEVICE); + } + try { + const key: string = await cryptoWorker.decryptB64( + keyAttributes.encryptedKey, + keyAttributes.keyDecryptionNonce, + kek + ); + callback(true, key, passphrase); + } catch (e) { + logError(e, 'user entered a wrong password'); + throw Error(CustomError.INCORRECT_PASSWORD); + } + } catch (e) { + switch (e.message) { + case CustomError.WEAK_DEVICE: + setFieldError(constants.WEAK_DEVICE); + break; + case CustomError.INCORRECT_PASSWORD: + setFieldError(constants.INCORRECT_PASSPHRASE); + break; + default: + setFieldError(`${constants.UNKNOWN_ERROR} ${e.message}`); + } + } + }; + + return ( + paypal@ente.io to manage your - subscription + {provider}@ente.io{' '} + to manage your subscription ), - PAYPAL_MANAGE_NOT_SUPPORTED: 'Manage paypal plan', RENAME: 'Rename', RENAME_COLLECTION: 'Rename album', DELETE_COLLECTION_TITLE: 'Delete album?', From 2316d18384fad1984e195fbc14a8418f3fcdcaa3 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 13 Sep 2022 13:20:09 +0530 Subject: [PATCH 270/295] update mobile subscription error message --- src/components/pages/gallery/PlanSelector/card/index.tsx | 6 +++--- src/utils/strings/englishConstants.tsx | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/pages/gallery/PlanSelector/card/index.tsx b/src/components/pages/gallery/PlanSelector/card/index.tsx index d03985c4a53dac578103fa324c1c268d0c661699..e242e51b9985f896302fbe64e4c348fbe6bb4d9a 100644 --- a/src/components/pages/gallery/PlanSelector/card/index.tsx +++ b/src/components/pages/gallery/PlanSelector/card/index.tsx @@ -108,9 +108,9 @@ function PlanSelectorCard(props: Props) { !isSubscriptionCancelled(subscription) ) { appContext.setDialogMessage({ - title: constants.ERROR, - content: constants.CANCEL_SUBSCRIPTION_ON_MOBILE, - close: { variant: 'danger' }, + title: constants.CANCEL_SUBSCRIPTION_ON_MOBILE, + content: constants.CANCEL_SUBSCRIPTION_ON_MOBILE_MESSAGE, + close: { variant: 'secondary' }, }); } else if ( hasPaidSubscription(subscription) && diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx index a81baafbfefa62403118713722971fcbb421fed4..500b38e1ce4ca65c73ae76778f86df5dbc588926 100644 --- a/src/utils/strings/englishConstants.tsx +++ b/src/utils/strings/englishConstants.tsx @@ -338,7 +338,8 @@ const englishConstants = { SUBSCRIPTION_ACTIVATE_FAILED: 'Failed to reactivate subscription renewals', SUBSCRIPTION_PURCHASE_SUCCESS_TITLE: 'Thank you', - CANCEL_SUBSCRIPTION_ON_MOBILE: + CANCEL_SUBSCRIPTION_ON_MOBILE: 'Cancel mobile subscription', + CANCEL_SUBSCRIPTION_ON_MOBILE_MESSAGE: 'Please cancel your subscription from the mobile app to activate a subscription here', MANAGE_NOT_SUPPORTED_MESSAGE: (provider) => ( <> From 55f2a6b07a55184ab2122d730642b80ab508dc7b Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 13 Sep 2022 13:28:13 +0530 Subject: [PATCH 271/295] rearrange checks --- .../pages/gallery/PlanSelector/card/index.tsx | 55 +++++++++---------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/src/components/pages/gallery/PlanSelector/card/index.tsx b/src/components/pages/gallery/PlanSelector/card/index.tsx index e242e51b9985f896302fbe64e4c348fbe6bb4d9a..e59343004d556e382147d4f6b7d0bff51eaa706b 100644 --- a/src/components/pages/gallery/PlanSelector/card/index.tsx +++ b/src/components/pages/gallery/PlanSelector/card/index.tsx @@ -104,25 +104,20 @@ function PlanSelectorCard(props: Props) { async function onPlanSelect(plan: Plan) { if ( - hasMobileSubscription(subscription) && - !isSubscriptionCancelled(subscription) + !hasPaidSubscription(subscription) || + isSubscriptionCancelled(subscription) ) { - appContext.setDialogMessage({ - title: constants.CANCEL_SUBSCRIPTION_ON_MOBILE, - content: constants.CANCEL_SUBSCRIPTION_ON_MOBILE_MESSAGE, - close: { variant: 'secondary' }, - }); - } else if ( - hasPaidSubscription(subscription) && - !isSubscriptionCancelled(subscription) - ) { - appContext.setDialogMessage({ - title: constants.MANAGE_PLAN, - content: constants.MANAGE_NOT_SUPPORTED_MESSAGE( - subscription.paymentProvider - ), - close: { variant: 'secondary' }, - }); + try { + props.setLoading(true); + await billingService.buySubscription(plan.stripeID); + } catch (e) { + props.setLoading(false); + appContext.setDialogMessage({ + title: constants.ERROR, + content: constants.SUBSCRIPTION_PURCHASE_FAILED, + close: { variant: 'danger' }, + }); + } } else if (hasStripeSubscription(subscription)) { appContext.setDialogMessage({ title: `${constants.CONFIRM} ${reverseString( @@ -142,18 +137,20 @@ function PlanSelectorCard(props: Props) { }, close: { text: constants.CANCEL }, }); + } else if (hasMobileSubscription(subscription)) { + appContext.setDialogMessage({ + title: constants.CANCEL_SUBSCRIPTION_ON_MOBILE, + content: constants.CANCEL_SUBSCRIPTION_ON_MOBILE_MESSAGE, + close: { variant: 'secondary' }, + }); } else { - try { - props.setLoading(true); - await billingService.buySubscription(plan.stripeID); - } catch (e) { - props.setLoading(false); - appContext.setDialogMessage({ - title: constants.ERROR, - content: constants.SUBSCRIPTION_PURCHASE_FAILED, - close: { variant: 'danger' }, - }); - } + appContext.setDialogMessage({ + title: constants.MANAGE_PLAN, + content: constants.MANAGE_NOT_SUPPORTED_MESSAGE( + subscription.paymentProvider + ), + close: { variant: 'secondary' }, + }); } } From 74bdf37f062b8190ea575b1775458c7b025cca29 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 13 Sep 2022 13:38:27 +0530 Subject: [PATCH 272/295] update email to mail at for billing support --- src/components/pages/gallery/PlanSelector/card/index.tsx | 4 +--- src/utils/strings/englishConstants.tsx | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/components/pages/gallery/PlanSelector/card/index.tsx b/src/components/pages/gallery/PlanSelector/card/index.tsx index e59343004d556e382147d4f6b7d0bff51eaa706b..4af88bbed1e5397efb46b1c2d66fb93a5fea5194 100644 --- a/src/components/pages/gallery/PlanSelector/card/index.tsx +++ b/src/components/pages/gallery/PlanSelector/card/index.tsx @@ -146,9 +146,7 @@ function PlanSelectorCard(props: Props) { } else { appContext.setDialogMessage({ title: constants.MANAGE_PLAN, - content: constants.MANAGE_NOT_SUPPORTED_MESSAGE( - subscription.paymentProvider - ), + content: constants.MAIL_TO_MANAGE_SUBSCRIPTION, close: { variant: 'secondary' }, }); } diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx index 500b38e1ce4ca65c73ae76778f86df5dbc588926..c12bc15148d2610b56d6655d67c96482c29676e6 100644 --- a/src/utils/strings/englishConstants.tsx +++ b/src/utils/strings/englishConstants.tsx @@ -341,11 +341,11 @@ const englishConstants = { CANCEL_SUBSCRIPTION_ON_MOBILE: 'Cancel mobile subscription', CANCEL_SUBSCRIPTION_ON_MOBILE_MESSAGE: 'Please cancel your subscription from the mobile app to activate a subscription here', - MANAGE_NOT_SUPPORTED_MESSAGE: (provider) => ( + MAIL_TO_MANAGE_SUBSCRIPTION: ( <> Please contact us at{' '} - {provider}@ente.io{' '} - to manage your subscription + support@ente.io to + manage your subscription ), RENAME: 'Rename', From ed4cc28f90d9dc5ff26839175a33be2968935dde Mon Sep 17 00:00:00 2001 From: Manav Date: Tue, 13 Sep 2022 19:06:35 +0530 Subject: [PATCH 273/295] Update the README screenshots * Update the screenshot in the README (had forgotten to update this after the redesigned version had been launched). * Also add manual line breaks to increasing the spacing above the sections (this matches what is there in the frame README). --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d90d2e1340c0796559bf7883bda64263eaf9607a..ea27599daa815a02861d4c8d57167a0e7d813f5e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ We have open-source apps across [Android](https://github.com/ente-io/frame), [iO This repository contains the code for our web app, built with a lot of ❤️, and a little bit of JavaScript.


-![App Screenshots](https://user-images.githubusercontent.com/1161789/154797467-a2c14f13-6b04-4282-ab61-f6a9f60c2026.png) + +![App Screenshots](https://user-images.githubusercontent.com/24503581/189914045-9d4e9c44-37c6-4ac6-9e17-d8c37aee1e08.png) ## ✨ Features @@ -19,10 +20,14 @@ This repository contains the code for our web app, built with a lot of ❤️, a - EXIF viewer - Zero third-party tracking / analytics +
+ ## 💻 Deployed Application The deployed application is accessible @ [web.ente.io](https://web.ente.io). +
+ ## 🧑‍💻 Building from source 1. Clone this repository with `git clone git@github.com:ente-io/bada-frame.git` @@ -32,26 +37,36 @@ The deployed application is accessible @ [web.ente.io](https://web.ente.io). Open [http://localhost:3000](http://localhost:3000) on your browser to see the live application. +
+ ## 🙋 Help We provide human support to our customers. Please write to [support@ente.io](mailto:support@ente.io) sharing as many details as possible about whatever it is that you need help with, and we will get back to you as soon as possible. +
+ ## 🧭 Roadmap We maintain a public roadmap, that's driven by our community @ [roadmap.ente.io](https://roadmap.ente.io). +
+ ## 🤗 Support If you like this project, please consider upgrading to a paid subscription. If you would like to motivate us to keep building, you can do so by [starring](https://github.com/ente-io/bada-frame/stargazers) this project. +
+ ## ❤️ Join the Community Follow us on [Twitter](https://twitter.com/enteio) and join [r/enteio](https://reddit.com/r/enteio) to get regular updates, connect with other customers, and discuss your ideas. An important part of our journey is to build better software by consistently listening to community feedback. Please feel free to [share your thoughts](mailto:feedback@ente.io) with us at any time. +
+ --- Cross-browser testing provided by From 65823eeaa5dcc9151fad48d95ac9754742e706eb Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 14 Sep 2022 11:07:49 +0530 Subject: [PATCH 274/295] fix verification data case --- src/services/billingService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/billingService.ts b/src/services/billingService.ts index 911f8be508032a72fa4ec63d23d9ce18cb10c7cc..5d95e345a889a307edbbea66257175ea1672c615 100644 --- a/src/services/billingService.ts +++ b/src/services/billingService.ts @@ -133,7 +133,7 @@ class billingService { { paymentProvider: 'stripe', productID: null, - VerificationData: sessionID, + verificationData: sessionID, }, null, { From 4a67c76cb56ee8cdcdf737ff1b404bb04a657212 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 15 Sep 2022 14:26:50 +0530 Subject: [PATCH 275/295] don't use user filename as identifier while conversion --- src/services/ffmpeg/ffmpegClient.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/services/ffmpeg/ffmpegClient.ts b/src/services/ffmpeg/ffmpegClient.ts index 7aa7a29b042eeb9cd8504d0165e1150a1751c48b..6f59a7f5c2b2a265df37c6befe8e60c501244067 100644 --- a/src/services/ffmpeg/ffmpegClient.ts +++ b/src/services/ffmpeg/ffmpegClient.ts @@ -22,7 +22,9 @@ class FFmpegClient { async generateThumbnail(file: File) { await this.ready; - const inputFileName = `${Date.now().toString()}-${file.name}`; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [name, ext] = splitFilenameAndExtension(file.name); + const inputFileName = `${Date.now().toString()}-input.${ext}`; const thumbFileName = `${Date.now().toString()}-thumb.jpeg`; this.ffmpeg.FS( 'writeFile', @@ -57,7 +59,9 @@ class FFmpegClient { async extractVideoMetadata(file: File) { await this.ready; - const inputFileName = `${Date.now().toString()}-${file.name}`; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [name, ext] = splitFilenameAndExtension(file.name); + const inputFileName = `${Date.now().toString()}-input.${ext}`; const outFileName = `${Date.now().toString()}-metadata.txt`; this.ffmpeg.FS( 'writeFile', @@ -105,3 +109,13 @@ class FFmpegClient { } export default FFmpegClient; + +export function splitFilenameAndExtension(filename: string): [string, string] { + const lastDotPosition = filename.lastIndexOf('.'); + if (lastDotPosition === -1) return [filename, null]; + else + return [ + filename.slice(0, lastDotPosition), + filename.slice(lastDotPosition + 1), + ]; +} From 00a64b4c8c00609c10a30e32cc3c9f9468db9d62 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 15 Sep 2022 14:30:28 +0530 Subject: [PATCH 276/295] move util --- src/services/ffmpeg/ffmpegClient.ts | 15 ++++----------- src/utils/ffmpeg/index.ts | 10 ++++++++++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/services/ffmpeg/ffmpegClient.ts b/src/services/ffmpeg/ffmpegClient.ts index 6f59a7f5c2b2a265df37c6befe8e60c501244067..b1787de4e8c5d6cbe35b1bfce079034acb38d74b 100644 --- a/src/services/ffmpeg/ffmpegClient.ts +++ b/src/services/ffmpeg/ffmpegClient.ts @@ -1,6 +1,9 @@ import { createFFmpeg, FFmpeg } from 'ffmpeg-wasm'; import { getUint8ArrayView } from 'services/readerService'; -import { parseFFmpegExtractedMetadata } from 'utils/ffmpeg'; +import { + parseFFmpegExtractedMetadata, + splitFilenameAndExtension, +} from 'utils/ffmpeg'; class FFmpegClient { private ffmpeg: FFmpeg; @@ -109,13 +112,3 @@ class FFmpegClient { } export default FFmpegClient; - -export function splitFilenameAndExtension(filename: string): [string, string] { - const lastDotPosition = filename.lastIndexOf('.'); - if (lastDotPosition === -1) return [filename, null]; - else - return [ - filename.slice(0, lastDotPosition), - filename.slice(lastDotPosition + 1), - ]; -} diff --git a/src/utils/ffmpeg/index.ts b/src/utils/ffmpeg/index.ts index c61d3f89fac406f3252e6942b9e75c6f1d87c331..916806c3e7d918864dbaf110d1440d5b7a6ffe65 100644 --- a/src/utils/ffmpeg/index.ts +++ b/src/utils/ffmpeg/index.ts @@ -61,3 +61,13 @@ function parseCreationTime(creationTime: string) { } return dateTime; } + +export function splitFilenameAndExtension(filename: string): [string, string] { + const lastDotPosition = filename.lastIndexOf('.'); + if (lastDotPosition === -1) return [filename, null]; + else + return [ + filename.slice(0, lastDotPosition), + filename.slice(lastDotPosition + 1), + ]; +} From a48fdc182af7d7aed004b44d6ac222bf759e845e Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 15 Sep 2022 14:31:12 +0530 Subject: [PATCH 277/295] use _ for dummy variable --- src/services/ffmpeg/ffmpegClient.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/ffmpeg/ffmpegClient.ts b/src/services/ffmpeg/ffmpegClient.ts index b1787de4e8c5d6cbe35b1bfce079034acb38d74b..cd48487446a92193445ae6231567cb4d341992dc 100644 --- a/src/services/ffmpeg/ffmpegClient.ts +++ b/src/services/ffmpeg/ffmpegClient.ts @@ -26,7 +26,7 @@ class FFmpegClient { async generateThumbnail(file: File) { await this.ready; // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [name, ext] = splitFilenameAndExtension(file.name); + const [_, ext] = splitFilenameAndExtension(file.name); const inputFileName = `${Date.now().toString()}-input.${ext}`; const thumbFileName = `${Date.now().toString()}-thumb.jpeg`; this.ffmpeg.FS( @@ -63,7 +63,7 @@ class FFmpegClient { async extractVideoMetadata(file: File) { await this.ready; // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [name, ext] = splitFilenameAndExtension(file.name); + const [_, ext] = splitFilenameAndExtension(file.name); const inputFileName = `${Date.now().toString()}-input.${ext}`; const outFileName = `${Date.now().toString()}-metadata.txt`; this.ffmpeg.FS( From 86dd9b726d94d0641bcea494a9973db7dbd14a29 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 15 Sep 2022 14:43:11 +0530 Subject: [PATCH 278/295] fix button text and casings --- .../pages/gallery/PlanSelector/manageSubscription/index.tsx | 4 ++-- src/utils/strings/englishConstants.tsx | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/pages/gallery/PlanSelector/manageSubscription/index.tsx b/src/components/pages/gallery/PlanSelector/manageSubscription/index.tsx index 89771f8f9e028b24bd04d04bbd59d149379b2018..66da8c05fa30408a06f673ee555d448b737f56da 100644 --- a/src/components/pages/gallery/PlanSelector/manageSubscription/index.tsx +++ b/src/components/pages/gallery/PlanSelector/manageSubscription/index.tsx @@ -77,7 +77,7 @@ function StripeSubscriptionOptions({ title: constants.CANCEL_SUBSCRIPTION, content: constants.CANCEL_SUBSCRIPTION_MESSAGE(), proceed: { - text: constants.CANCEL_SUBSCRIPTION, + text: constants.CANCEL, action: cancelSubscription.bind( null, appContext.setDialogMessage, @@ -87,7 +87,7 @@ function StripeSubscriptionOptions({ variant: 'danger', }, close: { - text: constants.CANCEL, + text: constants.NEVERMIND, }, }); const openManagementPortal = updatePaymentMethod.bind( diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx index c12bc15148d2610b56d6655d67c96482c29676e6..3bb9e7fef944d8bf6d52a6da83d667f02233b93a 100644 --- a/src/utils/strings/englishConstants.tsx +++ b/src/utils/strings/englishConstants.tsx @@ -216,7 +216,7 @@ const englishConstants = { CHANGE: 'Change', CHANGE_EMAIL: 'Change email', OK: 'Ok', - SUCCESS: 'success', + SUCCESS: 'Success', ERROR: 'Error', MESSAGE: 'Message', INSTALL_MOBILE_APP: () => ( @@ -820,6 +820,7 @@ const englishConstants = { AUTHENTICATE: 'Authenticate', UPLOADED_TO_SINGLE_COLLECTION: 'Uploaded to single collection', UPLOADED_TO_SEPARATE_COLLECTIONS: 'Uploaded to separate collections', + NEVERMIND: 'Nevermind', }; export default englishConstants; From bf477b46e16450842b2bc0416fe63811e6e96b8f Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 15 Sep 2022 14:44:09 +0530 Subject: [PATCH 279/295] fix casing --- src/utils/strings/englishConstants.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx index 3bb9e7fef944d8bf6d52a6da83d667f02233b93a..cebaa653c103a377bbe7a9aeed120665ef46559a 100644 --- a/src/utils/strings/englishConstants.tsx +++ b/src/utils/strings/englishConstants.tsx @@ -294,7 +294,7 @@ const englishConstants = { <>

We've received your payment

- your subscription is valid till{' '} + Your subscription is valid till{' '} {dateString(expiryTime)}

From ec28259b8ad143ba556954c5decc2fe0c71f7842 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 15 Sep 2022 14:51:44 +0530 Subject: [PATCH 280/295] fix reactive subscription dialog --- .../PlanSelector/manageSubscription/index.tsx | 12 ++++++------ src/utils/strings/englishConstants.tsx | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/pages/gallery/PlanSelector/manageSubscription/index.tsx b/src/components/pages/gallery/PlanSelector/manageSubscription/index.tsx index 66da8c05fa30408a06f673ee555d448b737f56da..d08249d2a2e21826e0d207b3fffda2003aadf3fd 100644 --- a/src/components/pages/gallery/PlanSelector/manageSubscription/index.tsx +++ b/src/components/pages/gallery/PlanSelector/manageSubscription/index.tsx @@ -52,14 +52,14 @@ function StripeSubscriptionOptions({ }: Iprops) { const appContext = useContext(AppContext); - const confirmActivation = () => + const confirmReactivation = () => appContext.setDialogMessage({ - title: constants.CONFIRM_ACTIVATE_SUBSCRIPTION, - content: constants.ACTIVATE_SUBSCRIPTION_MESSAGE( + title: constants.REACTIVATE_SUBSCRIPTION, + content: constants.REACTIVATE_SUBSCRIPTION_MESSAGE( subscription.expiryTime ), proceed: { - text: constants.ACTIVATE_SUBSCRIPTION, + text: constants.REACTIVATE, action: activateSubscription.bind( null, appContext.setDialogMessage, @@ -100,8 +100,8 @@ function StripeSubscriptionOptions({ {isSubscriptionCancelled(subscription) ? ( - {constants.ACTIVATE_SUBSCRIPTION} + onClick={confirmReactivation}> + {constants.REACTIVATE_SUBSCRIPTION} ) : ( + REACTIVATE_SUBSCRIPTION: 'Reactivate subscription', + REACTIVATE: 'Reactivate ', + REACTIVATE_SUBSCRIPTION_MESSAGE: (expiryTime) => `Once reactivated, you will be billed on ${dateString(expiryTime)}`, SUBSCRIPTION_ACTIVATE_SUCCESS: 'Subscription activated successfully ', SUBSCRIPTION_ACTIVATE_FAILED: 'Failed to reactivate subscription renewals', From 0ff9ceece104f3e54b69f71527db030bee84e352 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 15 Sep 2022 14:52:39 +0530 Subject: [PATCH 281/295] fix casing --- src/utils/strings/englishConstants.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx index d1ce99b48585fe9beda1d97c7e05907269ce6f3c..a12f68ef3b11acc1e904a6f34e34d464f5bb17c2 100644 --- a/src/utils/strings/englishConstants.tsx +++ b/src/utils/strings/englishConstants.tsx @@ -324,7 +324,7 @@ const englishConstants = { All of your data will be deleted from our servers at the end of this billing period.

-

are you sure that you want to cancel your subscription?

+

Are you sure that you want to cancel your subscription?

), SUBSCRIPTION_CANCEL_FAILED: 'Failed to cancel subscription', From 3bf078b8aaad2c15c47c86d8d12f5060376819a1 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 15 Sep 2022 15:14:31 +0530 Subject: [PATCH 282/295] change back strings --- .../pages/gallery/PlanSelector/manageSubscription/index.tsx | 4 ++-- src/utils/strings/englishConstants.tsx | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/pages/gallery/PlanSelector/manageSubscription/index.tsx b/src/components/pages/gallery/PlanSelector/manageSubscription/index.tsx index d08249d2a2e21826e0d207b3fffda2003aadf3fd..5b9166e780e365a61f8db750ea1e3834b078d4b2 100644 --- a/src/components/pages/gallery/PlanSelector/manageSubscription/index.tsx +++ b/src/components/pages/gallery/PlanSelector/manageSubscription/index.tsx @@ -59,7 +59,7 @@ function StripeSubscriptionOptions({ subscription.expiryTime ), proceed: { - text: constants.REACTIVATE, + text: constants.REACTIVATE_SUBSCRIPTION, action: activateSubscription.bind( null, appContext.setDialogMessage, @@ -77,7 +77,7 @@ function StripeSubscriptionOptions({ title: constants.CANCEL_SUBSCRIPTION, content: constants.CANCEL_SUBSCRIPTION_MESSAGE(), proceed: { - text: constants.CANCEL, + text: constants.CANCEL_SUBSCRIPTION, action: cancelSubscription.bind( null, appContext.setDialogMessage, diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx index a12f68ef3b11acc1e904a6f34e34d464f5bb17c2..27f83056b78366d37696a677779dc0cd5155535d 100644 --- a/src/utils/strings/englishConstants.tsx +++ b/src/utils/strings/englishConstants.tsx @@ -331,7 +331,6 @@ const englishConstants = { SUBSCRIPTION_CANCEL_SUCCESS: 'Subscription canceled successfully', REACTIVATE_SUBSCRIPTION: 'Reactivate subscription', - REACTIVATE: 'Reactivate ', REACTIVATE_SUBSCRIPTION_MESSAGE: (expiryTime) => `Once reactivated, you will be billed on ${dateString(expiryTime)}`, SUBSCRIPTION_ACTIVATE_SUCCESS: 'Subscription activated successfully ', From df94f6a37d5d0fdf741dff7a2ebef1122dff183c Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 15 Sep 2022 15:19:01 +0530 Subject: [PATCH 283/295] make dialog options stacked --- src/components/DialogBox/base.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/DialogBox/base.tsx b/src/components/DialogBox/base.tsx index 6db198c753ee35f695740d6f169d07b86af221cc..395c55cc6f1e7a62e9c021332d44fba73e1e3b86 100644 --- a/src/components/DialogBox/base.tsx +++ b/src/components/DialogBox/base.tsx @@ -18,6 +18,12 @@ const DialogBoxBase = styled(Dialog)(({ theme }) => ({ '.MuiDialogTitle-root + .MuiDialogActions-root': { paddingTop: theme.spacing(3), }, + '& .MuiDialogActions-root': { + flexWrap: 'wrap-reverse', + }, + '& .MuiButton-root': { + margin: theme.spacing(0.5, 0), + }, })); export default DialogBoxBase; From 12f2b7d198f3bbbde00bca19025343db06248bf1 Mon Sep 17 00:00:00 2001 From: Manav Date: Thu, 15 Sep 2022 16:46:26 +0530 Subject: [PATCH 284/295] Add the bundle ID of the US mobile app to apple site association --- public/.well-known/apple-app-site-association | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/.well-known/apple-app-site-association b/public/.well-known/apple-app-site-association index 8e87b1279af566de44998822ae88d6438662147b..265f647daaf232aa2600dbc4079da53d009bd34f 100644 --- a/public/.well-known/apple-app-site-association +++ b/public/.well-known/apple-app-site-association @@ -1,7 +1,8 @@ { "webcredentials": { "apps": [ + "6Z68YJY9Q2.io.ente.frame", "2BUSYC7FN9.io.ente.frame" ] } -} \ No newline at end of file +} From d0737030aaaf48f3390fece8935141adc8a4d39f Mon Sep 17 00:00:00 2001 From: Abhinav Date: Fri, 16 Sep 2022 15:57:58 +0530 Subject: [PATCH 285/295] fix hasNonSystemCollections check --- src/components/Collections/index.tsx | 4 ++-- src/pages/gallery/index.tsx | 6 ++++-- src/utils/collection/index.ts | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/components/Collections/index.tsx b/src/components/Collections/index.tsx index 06d16798d200319bcae52c5f2bf4919ddfb8ec6a..3c9cc1f3829c5c59a62ad3478017076f4504e514 100644 --- a/src/components/Collections/index.tsx +++ b/src/components/Collections/index.tsx @@ -8,7 +8,7 @@ import CollectionShare from 'components/Collections/CollectionShare'; import { SetCollectionNamerAttributes } from 'components/Collections/CollectionNamer'; import { ITEM_TYPE, TimeStampListItem } from 'components/PhotoList'; import { - hasNonEmptyCollections, + hasNonSystemCollections, isSystemCollection, shouldBeShownOnCollectionBar, } from 'utils/collection'; @@ -50,7 +50,7 @@ export default function Collections(props: Iprops) { const activeCollection = useRef(null); const shouldBeHidden = - isInSearchMode || hasNonEmptyCollections(collectionSummaries); + isInSearchMode || !hasNonSystemCollections(collectionSummaries); useEffect(() => { collectionsMap.current = new Map( diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index 44f698c287d560ee16cd8318b5d397b62f759d63..08baf3c359c3023596ed66787014167c91271372 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -73,7 +73,7 @@ import { getSelectedCollection, isFavoriteCollection, getArchivedCollections, - hasNonEmptyCollections, + hasNonSystemCollections, } from 'utils/collection'; import { logError } from 'utils/sentry'; import { @@ -669,7 +669,9 @@ export default function Gallery() { setShouldDisableDropzone={setShouldDisableDropzone} setFiles={setFiles} setCollections={setCollections} - isFirstUpload={hasNonEmptyCollections(collectionSummaries)} + isFirstUpload={ + !hasNonSystemCollections(collectionSummaries) + } webFileSelectorFiles={webFileSelectorFiles} webFolderSelectorFiles={webFolderSelectorFiles} dragAndDropFiles={dragAndDropFiles} diff --git a/src/utils/collection/index.ts b/src/utils/collection/index.ts index 97e5e8eaa5c610fbe92d91bd0b67a7e8f3ef51b0..1743e2c91cc8d0c952ffc21e8225660c25e97fb8 100644 --- a/src/utils/collection/index.ts +++ b/src/utils/collection/index.ts @@ -197,10 +197,10 @@ export const getArchivedCollections = (collections: Collection[]) => { ); }; -export const hasNonEmptyCollections = ( +export const hasNonSystemCollections = ( collectionSummaries: CollectionSummaries ) => { - return collectionSummaries?.size <= 3; + return collectionSummaries?.size > 3; }; export const isUploadAllowedCollection = (type: CollectionSummaryType) => { From c5b8e3fac0b0505332a4d1508e5e1e0bef6a721b Mon Sep 17 00:00:00 2001 From: Abhinav Date: Fri, 16 Sep 2022 16:55:47 +0530 Subject: [PATCH 286/295] fix show nothing to see here me --- src/components/PhotoList.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/PhotoList.tsx b/src/components/PhotoList.tsx index 72a428af1e0f86344b2626fcb10f3eb9e2e9d319..59003916e411fd5fd64297dae1872d7e40bbc190 100644 --- a/src/components/PhotoList.tsx +++ b/src/components/PhotoList.tsx @@ -220,7 +220,7 @@ export function PhotoList({ if (!skipMerge) { timeStampList = mergeTimeStampList(timeStampList, columns); } - if (timeStampList.length === 0) { + if (timeStampList.length === 1) { timeStampList.push(getEmptyListItem()); } if ( @@ -573,9 +573,6 @@ export function PhotoList({ return listItem.item; } }; - if (!timeStampList?.length) { - return <>; - } return ( Date: Fri, 16 Sep 2022 16:56:17 +0530 Subject: [PATCH 287/295] fix setPhotoListHeader --- src/components/Collections/index.tsx | 51 +++++++++++++--------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/src/components/Collections/index.tsx b/src/components/Collections/index.tsx index 3c9cc1f3829c5c59a62ad3478017076f4504e514..09d4ac1c82714f854a9ae512b248acf9e505443f 100644 --- a/src/components/Collections/index.tsx +++ b/src/components/Collections/index.tsx @@ -49,8 +49,10 @@ export default function Collections(props: Iprops) { const collectionsMap = useRef>(new Map()); const activeCollection = useRef(null); - const shouldBeHidden = - isInSearchMode || !hasNonSystemCollections(collectionSummaries); + const shouldBeHidden = useMemo( + () => isInSearchMode || !hasNonSystemCollections(collectionSummaries), + [isInSearchMode, collectionSummaries] + ); useEffect(() => { collectionsMap.current = new Map( @@ -72,31 +74,26 @@ export default function Collections(props: Iprops) { [collectionSortBy, collectionSummaries] ); - useEffect( - () => - !shouldBeHidden && - setPhotoListHeader({ - item: ( - setActiveCollectionID(ALL_SECTION)} - showCollectionShareModal={() => - setCollectionShareModalView(true) - } - /> - ), - itemType: ITEM_TYPE.OTHER, - height: 68, - }), - [collectionSummaries, activeCollectionID, shouldBeHidden] - ); + useEffect(() => { + setPhotoListHeader({ + item: ( + setActiveCollectionID(ALL_SECTION)} + showCollectionShareModal={() => + setCollectionShareModalView(true) + } + /> + ), + itemType: ITEM_TYPE.OTHER, + height: 68, + }); + }, [collectionSummaries, activeCollectionID, shouldBeHidden]); if (shouldBeHidden) { return <>; From 3cd6a5e5ae3a3443caef4f53172f58c05ac8451d Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 17 Sep 2022 12:40:19 +0530 Subject: [PATCH 288/295] revert unwanted change --- src/components/PhotoList.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/PhotoList.tsx b/src/components/PhotoList.tsx index 59003916e411fd5fd64297dae1872d7e40bbc190..b2157f12cce6fb338bc22fec7c5cf311a5cc1cf4 100644 --- a/src/components/PhotoList.tsx +++ b/src/components/PhotoList.tsx @@ -574,6 +574,10 @@ export function PhotoList({ } }; + if (!timeStampList?.length) { + return <>; + } + return ( Date: Sat, 17 Sep 2022 13:04:03 +0530 Subject: [PATCH 289/295] don't hide collection bar if user not in all section --- src/components/Collections/index.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/Collections/index.tsx b/src/components/Collections/index.tsx index 09d4ac1c82714f854a9ae512b248acf9e505443f..b60e93e0510137e35408861710cf6a046469e860 100644 --- a/src/components/Collections/index.tsx +++ b/src/components/Collections/index.tsx @@ -50,8 +50,11 @@ export default function Collections(props: Iprops) { const activeCollection = useRef(null); const shouldBeHidden = useMemo( - () => isInSearchMode || !hasNonSystemCollections(collectionSummaries), - [isInSearchMode, collectionSummaries] + () => + isInSearchMode || + (!hasNonSystemCollections(collectionSummaries) && + activeCollectionID === ALL_SECTION), + [isInSearchMode, collectionSummaries, activeCollectionID] ); useEffect(() => { @@ -93,7 +96,7 @@ export default function Collections(props: Iprops) { itemType: ITEM_TYPE.OTHER, height: 68, }); - }, [collectionSummaries, activeCollectionID, shouldBeHidden]); + }, [collectionSummaries, activeCollectionID]); if (shouldBeHidden) { return <>; From b2bd139c2bcafa115a73fcc3e12fa549ed6731a0 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 17 Sep 2022 13:18:04 +0530 Subject: [PATCH 290/295] add batching to delete from trash --- src/services/fileService.ts | 41 +++++++++++++++++++++++++++++-------- src/types/file/index.ts | 4 ++++ 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/services/fileService.ts b/src/services/fileService.ts index e3a13e09093646912f4f4459222c8b4c0b6f4b41..c6ddb76dea14c0115a576f9f36d5574d1803da50 100644 --- a/src/services/fileService.ts +++ b/src/services/fileService.ts @@ -13,7 +13,7 @@ import { sortFiles, } from 'utils/file'; import CryptoWorker from 'utils/crypto'; -import { EnteFile, TrashRequest } from 'types/file'; +import { DeleteFilesRequest, EnteFile, TrashRequest } from 'types/file'; import { SetFiles } from 'types/gallery'; import { MAX_TRASH_BATCH_SIZE } from 'constants/file'; import { BulkUpdateMagicMetadataRequest } from 'types/magicMetadata'; @@ -199,20 +199,43 @@ export const trashFiles = async (filesToTrash: EnteFile[]) => { } }; -export const deleteFromTrash = async (filesToDelete: number[]) => { +export const batchAndDeleteFromTrash = async (filesToDelete: number[]) => { try { const token = getToken(); if (!token) { return; } - await HTTPService.post( - `${ENDPOINT}/trash/delete`, - { fileIDs: filesToDelete }, - null, - { - 'X-Auth-Token': token, + + const deleteBatch: DeleteFilesRequest = { + fileIDs: [], + }; + + for (const fileID of filesToDelete) { + deleteBatch.fileIDs.push(fileID); + + if (deleteBatch.fileIDs.length >= MAX_TRASH_BATCH_SIZE) { + await deleteFromTrash(token, deleteBatch); + deleteBatch.fileIDs = []; } - ); + } + + if (deleteBatch.fileIDs.length > 0) { + await deleteFromTrash(token, deleteBatch); + } + } catch (e) { + logError(e, 'batchAndDeleteFromTrash failed'); + throw e; + } +}; + +export const deleteFromTrash = async ( + token: string, + deleteBatch: DeleteFilesRequest +) => { + try { + await HTTPService.post(`${ENDPOINT}/trash/delete`, deleteBatch, null, { + 'X-Auth-Token': token, + }); } catch (e) { logError(e, 'delete from trash failed'); throw e; diff --git a/src/types/file/index.ts b/src/types/file/index.ts index 1bc7a8d0ab2acc23841874de93064bbeb8e477b0..d5000683dcf7042607b9518e0b5c47bbab1e55c7 100644 --- a/src/types/file/index.ts +++ b/src/types/file/index.ts @@ -58,3 +58,7 @@ export interface TrashRequestItems { fileID: number; collectionID: number; } + +export interface DeleteFilesRequest { + fileIDs: number[]; +} From 83a10909af7adcee1e30843ed4011c7224d5330c Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 17 Sep 2022 13:21:45 +0530 Subject: [PATCH 291/295] rename function --- src/services/fileService.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/services/fileService.ts b/src/services/fileService.ts index c6ddb76dea14c0115a576f9f36d5574d1803da50..902aa881177ca02d68b3a60bfc5d200b3f9f7cad 100644 --- a/src/services/fileService.ts +++ b/src/services/fileService.ts @@ -199,7 +199,7 @@ export const trashFiles = async (filesToTrash: EnteFile[]) => { } }; -export const batchAndDeleteFromTrash = async (filesToDelete: number[]) => { +export const deleteFromTrash = async (filesToDelete: number[]) => { try { const token = getToken(); if (!token) { @@ -214,13 +214,13 @@ export const batchAndDeleteFromTrash = async (filesToDelete: number[]) => { deleteBatch.fileIDs.push(fileID); if (deleteBatch.fileIDs.length >= MAX_TRASH_BATCH_SIZE) { - await deleteFromTrash(token, deleteBatch); + await deleteBatchFromTrash(token, deleteBatch); deleteBatch.fileIDs = []; } } if (deleteBatch.fileIDs.length > 0) { - await deleteFromTrash(token, deleteBatch); + await deleteBatchFromTrash(token, deleteBatch); } } catch (e) { logError(e, 'batchAndDeleteFromTrash failed'); @@ -228,7 +228,7 @@ export const batchAndDeleteFromTrash = async (filesToDelete: number[]) => { } }; -export const deleteFromTrash = async ( +const deleteBatchFromTrash = async ( token: string, deleteBatch: DeleteFilesRequest ) => { From a0e2d977e3bdc6fc6033c34a853f20f8006c8797 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 17 Sep 2022 13:23:09 +0530 Subject: [PATCH 292/295] update error logging --- src/services/fileService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/fileService.ts b/src/services/fileService.ts index 902aa881177ca02d68b3a60bfc5d200b3f9f7cad..216b479262aa0eef8fe51bc7abc3f7aaebbc596d 100644 --- a/src/services/fileService.ts +++ b/src/services/fileService.ts @@ -223,7 +223,7 @@ export const deleteFromTrash = async (filesToDelete: number[]) => { await deleteBatchFromTrash(token, deleteBatch); } } catch (e) { - logError(e, 'batchAndDeleteFromTrash failed'); + logError(e, 'deleteFromTrash failed'); throw e; } }; @@ -237,7 +237,7 @@ const deleteBatchFromTrash = async ( 'X-Auth-Token': token, }); } catch (e) { - logError(e, 'delete from trash failed'); + logError(e, 'deleteBatchFromTrash failed'); throw e; } }; From de858fd3883258b1e7f836a5911dffe8ca078989 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 17 Sep 2022 13:25:15 +0530 Subject: [PATCH 293/295] remove unnecessary empty line --- src/services/fileService.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/services/fileService.ts b/src/services/fileService.ts index 216b479262aa0eef8fe51bc7abc3f7aaebbc596d..80b2682c58c84466f92f861610da0fd733afdc83 100644 --- a/src/services/fileService.ts +++ b/src/services/fileService.ts @@ -205,20 +205,16 @@ export const deleteFromTrash = async (filesToDelete: number[]) => { if (!token) { return; } - const deleteBatch: DeleteFilesRequest = { fileIDs: [], }; - for (const fileID of filesToDelete) { deleteBatch.fileIDs.push(fileID); - if (deleteBatch.fileIDs.length >= MAX_TRASH_BATCH_SIZE) { await deleteBatchFromTrash(token, deleteBatch); deleteBatch.fileIDs = []; } } - if (deleteBatch.fileIDs.length > 0) { await deleteBatchFromTrash(token, deleteBatch); } From 9055f67ff4e6775c93b71e3b073f2988d78873e7 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 17 Sep 2022 13:41:03 +0530 Subject: [PATCH 294/295] remove DeleteFilesRequest interface --- src/services/fileService.ts | 30 +++++++++++++++--------------- src/types/file/index.ts | 4 ---- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/services/fileService.ts b/src/services/fileService.ts index 80b2682c58c84466f92f861610da0fd733afdc83..ed92ffe1ae0a0faf74470a9f54f3a213dd0f71d5 100644 --- a/src/services/fileService.ts +++ b/src/services/fileService.ts @@ -13,7 +13,7 @@ import { sortFiles, } from 'utils/file'; import CryptoWorker from 'utils/crypto'; -import { DeleteFilesRequest, EnteFile, TrashRequest } from 'types/file'; +import { EnteFile, TrashRequest } from 'types/file'; import { SetFiles } from 'types/gallery'; import { MAX_TRASH_BATCH_SIZE } from 'constants/file'; import { BulkUpdateMagicMetadataRequest } from 'types/magicMetadata'; @@ -205,17 +205,15 @@ export const deleteFromTrash = async (filesToDelete: number[]) => { if (!token) { return; } - const deleteBatch: DeleteFilesRequest = { - fileIDs: [], - }; + let deleteBatch: number[]; for (const fileID of filesToDelete) { - deleteBatch.fileIDs.push(fileID); - if (deleteBatch.fileIDs.length >= MAX_TRASH_BATCH_SIZE) { + deleteBatch.push(fileID); + if (deleteBatch.length >= MAX_TRASH_BATCH_SIZE) { await deleteBatchFromTrash(token, deleteBatch); - deleteBatch.fileIDs = []; + deleteBatch = []; } } - if (deleteBatch.fileIDs.length > 0) { + if (deleteBatch.length > 0) { await deleteBatchFromTrash(token, deleteBatch); } } catch (e) { @@ -224,14 +222,16 @@ export const deleteFromTrash = async (filesToDelete: number[]) => { } }; -const deleteBatchFromTrash = async ( - token: string, - deleteBatch: DeleteFilesRequest -) => { +const deleteBatchFromTrash = async (token: string, deleteBatch: number[]) => { try { - await HTTPService.post(`${ENDPOINT}/trash/delete`, deleteBatch, null, { - 'X-Auth-Token': token, - }); + await HTTPService.post( + `${ENDPOINT}/trash/delete`, + { fileIDs: deleteBatch }, + null, + { + 'X-Auth-Token': token, + } + ); } catch (e) { logError(e, 'deleteBatchFromTrash failed'); throw e; diff --git a/src/types/file/index.ts b/src/types/file/index.ts index d5000683dcf7042607b9518e0b5c47bbab1e55c7..1bc7a8d0ab2acc23841874de93064bbeb8e477b0 100644 --- a/src/types/file/index.ts +++ b/src/types/file/index.ts @@ -58,7 +58,3 @@ export interface TrashRequestItems { fileID: number; collectionID: number; } - -export interface DeleteFilesRequest { - fileIDs: number[]; -} From 8df9ebd44aca1ea2fd8523fb210a32cddb7aa026 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 17 Sep 2022 13:47:55 +0530 Subject: [PATCH 295/295] fix deleteFromTrash deleteBatch not intiialised --- src/services/fileService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/fileService.ts b/src/services/fileService.ts index ed92ffe1ae0a0faf74470a9f54f3a213dd0f71d5..f2935ce044ea1f449f7801acd058dbc47e1be79a 100644 --- a/src/services/fileService.ts +++ b/src/services/fileService.ts @@ -205,7 +205,7 @@ export const deleteFromTrash = async (filesToDelete: number[]) => { if (!token) { return; } - let deleteBatch: number[]; + let deleteBatch: number[] = []; for (const fileID of filesToDelete) { deleteBatch.push(fileID); if (deleteBatch.length >= MAX_TRASH_BATCH_SIZE) {