-
-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: handle getFile returning null and close #106 #107
Conversation
Pull Request Test Coverage Report for Build 12030921930Details
💛 - Coveralls |
dda503e
to
a7357e4
Compare
I tried to refactor the logic as much as possible without touching any of the parameters or side-effects passed into This is what I came up with: async function fromDataTransferItem(item: DataTransferItem, entry?: FileSystemEntry | null) {
const handle = await item.getAsFileSystemHandle?.();
if (handle && isFileHandler(handle)) {
const file = await handle.getFile();
file.handle = handle;
return toFileWithPath(file);
}
const file = item.getAsFile();
if (!file) {
throw new Error(`${item} is not a File`);
}
return toFileWithPath(file, entry?.fullPath ?? undefined);
}
function isFileHandler(handle: FileSystemFileHandle | FileSystemDirectoryHandle): handle is FileSystemFileHandle {
return handle.kind === 'file';
}
declare global {
interface DataTransferItem {
// This method is not yet widely supported in all browsers, and is thus marked as optional.
// See: https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/getAsFileSystemHandle
getAsFileSystemHandle?(): Promise<FileSystemFileHandle | FileSystemDirectoryHandle | null>;
}
} WDYT? |
This sounds lovely Thank you 😄 |
@jonkoops thanks, but as far as I can see/remember, async function getDataTransferFiles(dt: DataTransfer, type: string) {
// IE11 does not support dataTransfer.items
// See https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/items#Browser_compatibility
if (dt.items) {
const items = fromList<DataTransferItem>(dt.items)
.filter(item => item.kind === 'file');
// According to https://html.spec.whatwg.org/multipage/dnd.html#dndevents,
// only 'dragstart' and 'drop' has access to the data (source node)
if (type !== 'drop') {
return items;
}
const files = await Promise.all(items.map(toFilePromises)); so in practice, items that are not files should not make it through. So it makes me wonder what else is going on there. @buenjybar if you can, please share a bit more about your use case or maybe a codesandbox and the steps to reproduce so we can figure out what's going on. |
Got it yeah, I was going off a specific section of code without understanding the whole program fully, which seems to have guided me on some assumptions that were more defensive than required. In general I tend to use the types as guidance and do defensive programming where there is a possibility of a gap between the type and implementation. I'll do some testing to see if I can reproduce this issue. |
No worries. I appreciate all the help! That sounds good, but I still think that if @buenjybar would provide more context, it would be very helpful. |
here #108 this is the full project setup that is reproducing a production bug |
Thanks for taking the time to provide a reproducible example. We'll look into it. |
a7357e4
to
8ca297f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, let's get this landed.
I wonder if we should reject or go to |
You want to do the fallback solution I proposed instead? It would cover all the cases, but it is hard to tell if it would actually resolve the problem. I would agree with your earlier assessment that if |
Not sure how it was triggered, we tried investigating but couldn't find anything. IMO it makes sense to fallback to |
Ok. It sounds like the sensible thing todo is to go for a fallback. Let me add that. |
8ca297f
to
dd29335
Compare
Btw, I've added support for returning a custom error in that case where either we have |
@rolandjitsu could you give this one a rebase with |
const h = await (item as any).getAsFileSystemHandle(); | ||
if (h === null) { | ||
throw new Error(`${item} is not a File`); | ||
} | ||
// It seems that the handle can be `undefined` (see https://github.com/react-dropzone/file-selector/issues/120), | ||
// so we check if it isn't; if it is, the code path continues to the next API (`getAsFile`). | ||
if (h !== undefined) { | ||
const file = await h.getFile(); | ||
file.handle = h; | ||
return toFileWithPath(file); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't this be a safer fallback? Isn't it nice to try getFile
if getAsFileSystemHandle
does not return the expected data for some other unknown reason?
const h = await (item as any).getAsFileSystemHandle(); | |
if (h === null) { | |
throw new Error(`${item} is not a File`); | |
} | |
// It seems that the handle can be `undefined` (see https://github.com/react-dropzone/file-selector/issues/120), | |
// so we check if it isn't; if it is, the code path continues to the next API (`getAsFile`). | |
if (h !== undefined) { | |
const file = await h.getFile(); | |
file.handle = h; | |
return toFileWithPath(file); | |
} | |
const h = await (item as any).getAsFileSystemHandle(); | |
if(!h) { | |
const file = await h.getFile(); | |
if(!file) { | |
throw new Error(`${item} is not a File`); | |
} | |
file.handle = h; | |
return toFileWithPath(file); | |
} |
And then you can skip the
const file = item.getAsFile();
if (!file) {
throw new Error(`${item} is not a File`);
}
below, because it will always try getFile
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if(!h) {
const file = await h.getFile();
That will essentially throw an exception because it will evaluate if h
is undefined
or null
. We want the opposite of that. Note that getFile
and getAsFile
are 2 different APIs that exist on different objects.
It should already be rebased. |
🎉 This PR is included in version 2.1.2 🎉 The release is available on: Your semantic-release bot 📦🚀 |
🎉 This PR is included in version 2.1.2 🎉 The release is available on: Your semantic-release bot 📦🚀 |
What kind of change does this PR introduce?
Did you add tests for your changes?
If relevant, did you update the documentation?
Summary
Address #106.
Does this PR introduce a breaking change?
No.
Other information