Understand, document and fix

This commit is contained in:
Manav Rathi 2024-05-09 10:37:06 +05:30
parent ac67566f45
commit e92bbdb8c6
No known key found for this signature in database
2 changed files with 52 additions and 4 deletions

View file

@ -1,6 +1,8 @@
import { basename } from "@/next/file";
import log from "@/next/log";
import type { CollectionMapping, Electron, ZipItem } from "@/next/types/ipc";
import { firstNonEmpty } from "@/utils/array";
import { ensure } from "@/utils/ensure";
import { CustomError } from "@ente/shared/error";
import { isPromise } from "@ente/shared/utils";
import DiscFullIcon from "@mui/icons-material/DiscFull";
@ -324,17 +326,17 @@ export default function Uploader({
// Trigger an upload when any of the dependencies change.
useEffect(() => {
// Re the paths:
// About the paths:
//
// - These are not necessarily the full paths. In particular, when
// running on the browser they'll be the relative paths (at best) or
// just the file-name otherwise.
//
// - All the paths use POSIX separators. See inline comments.
//
const allItemAndPaths = [
// See: [Note: webkitRelativePath]. In particular, they use POSIX
// separators.
webFiles.map((f) => [f, f.webkitRelativePath ?? f.name]),
// Relative path (using POSIX separators) or the file's name.
webFiles.map((f) => [f, pathLikeForWebFile(f)]),
// The paths we get from the desktop app all eventually come either
// from electron.selectDirectory or electron.pathForFile, both of
// which return POSIX paths.
@ -822,6 +824,37 @@ const desktopFilesAndZipItems = async (electron: Electron, files: File[]) => {
return { fileAndPaths, zipItems };
};
/**
* Return the relative path or name of a File object selected or
* drag-and-dropped on the web.
*
* There are three cases here:
*
* 1. If the user selects individual file(s), then the returned File objects
* will only have a `name`.
*
* 2. If the user selects directory(ies), then the returned File objects will
* have a `webkitRelativePath`. For more details, see [Note:
* webkitRelativePath]. In particular, these will POSIX separators.
*
* 3. If the user drags-and-drops, then the react-dropzone library that we use
* will internally convert `webkitRelativePath` to `path`, but otherwise it
* behaves same as case 2.
* https://github.com/react-dropzone/file-selector/blob/master/src/file.ts#L1214
*/
const pathLikeForWebFile = (file: File): string =>
ensure(
firstNonEmpty([
// We need to check first, since path is not a property of
// the standard File objects.
"path" in file && typeof file.path == "string"
? file.path
: undefined,
file.webkitRelativePath,
file.name,
]),
);
// This is used to prompt the user the make upload strategy choice
interface ImportSuggestion {
rootFolderName: string;

View file

@ -13,3 +13,18 @@ export const shuffled = <T>(xs: T[]) =>
.map((x) => [Math.random(), x])
.sort()
.map(([, x]) => x) as T[];
/**
* Return the first non-empty string from the given list of strings.
*
* This function is needed because the `a ?? b` idiom doesn't do what you'd
* expect when a is "". Perhaps the behaviour is wrong, perhaps the expecation
* is wrong; this function papers over the differences.
*
* If none of the strings are non-empty, or if there are no strings in the given
* array, return undefined.
*/
export const firstNonEmpty = (ss: (string | undefined)[]) => {
for (const s of ss) if (s && s.length > 0) return s;
return undefined;
};