diff --git a/web/apps/cast/src/types/upload/index.ts b/web/apps/cast/src/types/upload/index.ts index ef44b4a23..0e249846a 100644 --- a/web/apps/cast/src/types/upload/index.ts +++ b/web/apps/cast/src/types/upload/index.ts @@ -95,13 +95,6 @@ export interface ParsedExtractedMetadata { height: number; } -// This is used to prompt the user the make upload strategy choice -export interface ImportSuggestion { - rootFolderName: string; - hasNestedFolders: boolean; - hasRootLevelFileWithFolder: boolean; -} - export interface PublicUploadProps { token: string; passwordToken: string; diff --git a/web/apps/photos/src/components/Upload/Uploader.tsx b/web/apps/photos/src/components/Upload/Uploader.tsx index 1d95c9310..ad0ff15b1 100644 --- a/web/apps/photos/src/components/Upload/Uploader.tsx +++ b/web/apps/photos/src/components/Upload/Uploader.tsx @@ -5,11 +5,7 @@ import { CustomError } from "@ente/shared/error"; import { isPromise } from "@ente/shared/utils"; import DiscFullIcon from "@mui/icons-material/DiscFull"; import UserNameInputDialog from "components/UserNameInputDialog"; -import { - DEFAULT_IMPORT_SUGGESTION, - PICKED_UPLOAD_TYPE, - UPLOAD_STAGES, -} from "constants/upload"; +import { PICKED_UPLOAD_TYPE, UPLOAD_STAGES } from "constants/upload"; import { t } from "i18next"; import isElectron from "is-electron"; import { AppContext } from "pages/_app"; @@ -35,11 +31,7 @@ import { SetLoading, UploadTypeSelectorIntent, } from "types/gallery"; -import { - ElectronFile, - FileWithCollection, - ImportSuggestion, -} from "types/upload"; +import { ElectronFile, FileWithCollection } from "types/upload"; import { InProgressUpload, SegregatedFinishedUploads, @@ -53,9 +45,11 @@ import { getRootLevelFileWithFolderNotAllowMessage, } from "utils/ui"; import { + DEFAULT_IMPORT_SUGGESTION, filterOutSystemFiles, getImportSuggestion, groupFilesBasedOnParentFolder, + type ImportSuggestion, } from "utils/upload"; import { SetCollectionNamerAttributes } from "../Collections/CollectionNamer"; import { CollectionMappingChoiceModal } from "./CollectionMappingChoiceModal"; diff --git a/web/apps/photos/src/components/WatchFolder.tsx b/web/apps/photos/src/components/WatchFolder.tsx index 5715dfb45..f7951c5a8 100644 --- a/web/apps/photos/src/components/WatchFolder.tsx +++ b/web/apps/photos/src/components/WatchFolder.tsx @@ -1,4 +1,5 @@ import { ensureElectron } from "@/next/electron"; +import { basename } from "@/next/file"; import type { CollectionMapping, FolderWatch } from "@/next/types/ipc"; import { ensure } from "@/utils/ensure"; import { @@ -166,7 +167,7 @@ const WatchList: React.FC = ({ watches, removeWatch }) => { {watches.map((watch) => { return ( @@ -292,7 +293,7 @@ const EntryHeading: React.FC = ({ watch }) => { const appContext = useContext(AppContext); return ( - {watch.rootFolderName} + {basename(watch.folderPath)} {appContext.isFolderSyncRunning && watcher.isSyncingWatch(watch) && } diff --git a/web/apps/photos/src/constants/upload.ts b/web/apps/photos/src/constants/upload.ts index 6d9f63d78..1f8858bc3 100644 --- a/web/apps/photos/src/constants/upload.ts +++ b/web/apps/photos/src/constants/upload.ts @@ -1,11 +1,6 @@ import { ENCRYPTION_CHUNK_SIZE } from "@ente/shared/crypto/constants"; import { FILE_TYPE } from "constants/file"; -import { - FileTypeInfo, - ImportSuggestion, - Location, - ParsedExtractedMetadata, -} from "types/upload"; +import { FileTypeInfo, Location, ParsedExtractedMetadata } from "types/upload"; // list of format that were missed by type-detection for some files. export const WHITELISTED_FILE_FORMATS: FileTypeInfo[] = [ @@ -111,12 +106,6 @@ export const NULL_EXTRACTED_METADATA: ParsedExtractedMetadata = { export const A_SEC_IN_MICROSECONDS = 1e6; -export const DEFAULT_IMPORT_SUGGESTION: ImportSuggestion = { - rootFolderName: "", - hasNestedFolders: false, - hasRootLevelFileWithFolder: false, -}; - export const BLACK_THUMBNAIL_BASE64 = "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEB" + "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQ" + diff --git a/web/apps/photos/src/services/watch.ts b/web/apps/photos/src/services/watch.ts index 51d9484e6..c8f330386 100644 --- a/web/apps/photos/src/services/watch.ts +++ b/web/apps/photos/src/services/watch.ts @@ -115,9 +115,7 @@ class FolderWatcher { * collection do files belonging to nested directories go to. */ async addWatch(folderPath: string, mapping: CollectionMapping) { - const rootFolderName = folderPath.substring( - folderPath.lastIndexOf("/") + 1, - ); + const rootFolderName = basename(folderPath) await ensureElectron().addWatchMapping( rootFolderName, folderPath, diff --git a/web/apps/photos/src/types/upload/index.ts b/web/apps/photos/src/types/upload/index.ts index 3deab0ed7..72eef39f6 100644 --- a/web/apps/photos/src/types/upload/index.ts +++ b/web/apps/photos/src/types/upload/index.ts @@ -156,13 +156,6 @@ export interface ParsedExtractedMetadata { height: number; } -// This is used to prompt the user the make upload strategy choice -export interface ImportSuggestion { - rootFolderName: string; - hasNestedFolders: boolean; - hasRootLevelFileWithFolder: boolean; -} - export interface PublicUploadProps { token: string; passwordToken: string; diff --git a/web/apps/photos/src/utils/upload/index.ts b/web/apps/photos/src/utils/upload/index.ts index 49f39a676..1d7674165 100644 --- a/web/apps/photos/src/utils/upload/index.ts +++ b/web/apps/photos/src/utils/upload/index.ts @@ -1,19 +1,10 @@ import { basename, dirname } from "@/next/file"; import { FILE_TYPE } from "constants/file"; -import { - A_SEC_IN_MICROSECONDS, - DEFAULT_IMPORT_SUGGESTION, - PICKED_UPLOAD_TYPE, -} from "constants/upload"; +import { A_SEC_IN_MICROSECONDS, PICKED_UPLOAD_TYPE } from "constants/upload"; import isElectron from "is-electron"; import { exportMetadataDirectoryName } from "services/export"; import { EnteFile } from "types/file"; -import { - ElectronFile, - FileWithCollection, - ImportSuggestion, - Metadata, -} from "types/upload"; +import { ElectronFile, FileWithCollection, Metadata } from "types/upload"; const TYPE_JSON = "json"; const DEDUPE_COLLECTION = new Set(["icloud library", "icloudlibrary"]); @@ -120,6 +111,19 @@ export function areFileWithCollectionsSame( export const areAllInSameDirectory = (paths: string[]) => new Set(paths.map(dirname)).size == 1; +// This is used to prompt the user the make upload strategy choice +export interface ImportSuggestion { + rootFolderName: string; + hasNestedFolders: boolean; + hasRootLevelFileWithFolder: boolean; +} + +export const DEFAULT_IMPORT_SUGGESTION: ImportSuggestion = { + rootFolderName: "", + hasNestedFolders: false, + hasRootLevelFileWithFolder: false, +}; + export function getImportSuggestion( uploadType: PICKED_UPLOAD_TYPE, toUploadFiles: File[] | ElectronFile[], diff --git a/web/packages/next/types/ipc.ts b/web/packages/next/types/ipc.ts index 321fb2192..c2adc517b 100644 --- a/web/packages/next/types/ipc.ts +++ b/web/packages/next/types/ipc.ts @@ -300,6 +300,21 @@ export interface Electron { * The returned paths are guaranteed to use POSIX separators ('/'). */ findFiles: (folderPath: string) => Promise; + + /** + * Add a new folder watch for the given {@link folderPath}. + * + * This adds a new entry in the list of watches (persisting them on + * disk), and also starts immediately observing for file system events + * that happen within {@link folderPath}. + * + * @param collectionMapping Determines how nested directories (if any) + * get mapped to Ente collections. + */ + add: ( + folderPath: string, + collectionMapping: CollectionMapping, + ) => Promise; }; registerWatcherFunctions: ( @@ -394,6 +409,12 @@ export interface AppUpdate { * side. */ export interface FolderWatch { + /** + * Name of the root folder. + * + * This is just `basename(folderPath)`, but is retained as a precomputed + * property for convenience instead of needing to recompute it every time. + */ rootFolderName: string; /** * Specify if nested files should all be mapped to the same single root @@ -401,8 +422,17 @@ export interface FolderWatch { * files. @see {@link CollectionMapping}. */ collectionMapping: CollectionMapping; + /** + * The path to the (root) folder we are watching. + */ folderPath: string; + /** + * Files that have already been uploaded. + */ syncedFiles: FolderWatchSyncedFile[]; + /** + * Files (paths) that should be ignored when uploading. + */ ignoredFiles: string[]; }