WICG / file-system-access

Expose the file system on the user’s device, so Web apps can interoperate with the user’s native applications.
https://wicg.github.io/file-system-access/
Other
657 stars 65 forks source link

Access parent directory #193

Closed lukejagodzinski closed 2 years ago

lukejagodzinski commented 4 years ago

After opening directory with const handle = window.chooseFileSystemEntries({ type: "open-directory" }) I can access files in it using the handle.getEntries(). Now I would like to access the original directory by something like entry.parent or whatever API. That way it would be handy to create file explorer in web. After giving access to directory and its all descendants I might want to traverse this tree of files/directories. From what I see it's not possible right now without just storing handle to parent dir

jsejcksn commented 4 years ago

@lukejagodzinski What would be the value of entry.parent in the event that the file handle was obtained directly and the app doesn't have permission to access the parent?

lukejagodzinski commented 4 years ago

It could just be undefined or null whatever is consistent with other cases like that in the browser API. I think standard here is null.

Also in Node file system API it's nice that we have the .. file which points to parent. I'm ok with not having that kind of file as there is actually no such file in the directory named .. but being able to access parent is must have imho.

EDIT:

Here is a good example:

const div = document.createElement("div");
div.parentElement; // null

When an element is not placed in the DOM tree then its parent is null.

It could even be called entry.parentDirectory or entry.parentEntry? So that it's just clearer what parent are we talking here about.

mkruisselbrink commented 4 years ago

It seems like you could polyfill something like this yourself? Just wrap the methods that get a child entry with something that also sets a parent property on the returned child... Although of course that is just one possible meaning of what the "parent directory" of a handle would be. If a handle was received from a file picker, but the website also happens to have access to the parent directory already, should parent in that case return null or return the actual parent? And if two entries represent the same file, but have different parent directories, should isSameEntry still return true? Since it's not entirely obvious what to do in all edge cases, and this is something that at least in some form could be trivially implemented in javascript, I'd prefer not to add anything for this in the spec.

lukejagodzinski commented 4 years ago

I've already implemented my own parent solution and it works but it would be nice to have something like that to be built in.

I think if browser just happens to have access to parent directory I think it should be available in other entries. User can see what directories and files browser has access to, so he can always revoke access. The other option could be that if user is picking a new directory it could automatically revoke access to all previous directories/files. It could be file picker option. It might actually be something that user would prefer. When picking file I might think that previous directories access will be revoked. But it's acdifferent subject.

About the isSameEntry I haven't used it and I don't know how it works but how is it possible that same file might have two different parents?

Also about the entire file system API. I understand that there is no need to add some extra methods/properties that could be easily polyfilled. But notice that if it's not done then there will probably appear some higher level abstraction libraries that will have nicer API, maybe something more similar to Node.js fs. My problem with web APIs is that it's very often very complex and because of that a lot of people is making higher level abstractions and when there are several libraries, then instead of having one common way of doing things in a simple way, we have several competing "standards". Look at the jQuery example. In the past it made selecting HTML elements much easier and now we have querySelector(All) in the web which is doing similar thing. APIs should be simple and let developer cover most of the use cases.

jsejcksn commented 4 years ago

@lukejagodzinski That's what's great about foundational-level APIs: They provide only what's absolutely necessary and because of that, should be as performant as possible. Then other abstractions can provide tailored interfaces by application (at the cost of performance).

lukejagodzinski commented 4 years ago

@jsejcksn I get it and I like it too that API is bare minimum however I can give several examples of web APIs, that could be done in "manually", in a performant way but it's still there and it's done for convenience, I guess. So just saying :) I can live without the parent property, but it would be nice to have it. It seemed to me like trivial thing to add, but if you guys think otherwise then I'm not going to argue :) I don't know details of the spec and implementation.

jsejcksn commented 4 years ago

how is it possible that same file might have two different parents?

Hard links is one example, but I’m not exactly sure of the definition of file because I haven’t read that part of the spec yet either.

mkruisselbrink commented 4 years ago

It depends on how parent is defined. In the simple model where a parent is null for anything returned by showOpenFilePicker (regardless of if the website happens to have access to a parent directory of the file as well) it would be possible to get two different handles to what really is the same file on disk; but for on the parent is null, while for the other the parent is set. If instead we would support the much more complicated to implement model of trying to have the parent always set if it happens to be accessible to the website (which also has the downside of parent now no longer being a static property, but instead being something that can change; at least from null to non-null) it would indeed be harder for the parent to be different for two different handles representing the same file.

I'm not a fan of trying to return a parent if that directory just happens to be accessible by the website, even for new handles returned by a file picker. "is accessible" could be scoped to just the current frame (or agent), but then transferring a handle between frames (or storing in IndexedDB and loading it back in a different frame) could change if it has a parent or not. Or if "is accessible" is defined globally, we now have the problem of how to propagate state changes (i.e. a user picks a directory in showDirectoryPicker that is a parent of handles already available; those should now suddenly get a parent, but updating that property of objects in all frames and workers now gets really tricky, and will probably still result in some period of inconsistency until all event loops have executed whatever task we'd post to update these parent properties.

So having a parent property that matches what can be trivially implemented by javascript wouldn't be too hard to implement, but would also be of limited usefulness. And doing anything more would be really complicated to spec and implement.

lukejagodzinski commented 4 years ago

I would like to revisit this issue. I have a use case where accessing parent is must have for the UX to be right.

I want to implement directory flattening. So I click the FLATTEN DIRECTORY button. I open directory picker with window.showDirectoryPicker() to retrieve handle to directory X. Now I want to move all the files inside this (X) directory one level up. I can't do it because I don't have handle to that. I can't even show permission request prompt.

What I have to do now is just to change my entire UX. I have to request permission to parent directory first and show all files and directories to the user and let him/her choose directory to flatten. It doesn't really make sense to make such a complex UX.

Anoesj commented 4 years ago

You could require end users to open the parent directory of directory X, let's call it directory A. Then you would have a handle to the directory you want to move all the files from directory X to. You can't write to a directory that's above the directory you have a handle to anyway.

So if this is your start situation:

...and this is the desired end result:

...then the end user should open directory A, not directory X. Or am I missing something?


EDIT: I see you already figured that out, sorry. UX-wise I'd actually prefer the latter. I wouldn't expect a FLATTEN DIRECTORY button to move files outside of the selected directory anyway.

lukejagodzinski commented 4 years ago

@Anoesj honestly, I don't agree on UX. It's rather more intuitive to just select the directory you want to flatten. If in the app you have a button SELECT DIRECTORY TO FLATTEN then you would select the directory to flatten, that's it. Imagine an app where you select image file to edit and instead of selecting file you have to select parent directory and then display list of files and select image to edit. It's similar case.

Maybe it would be good to have an option in the select file/directory dialog that ask you for the permission to the parent directory of selected file/directory?

const parentHandle = showDirectoryPicker({ requestParentAccess: true });

But that would be a little bit misleading as selecting directory A would request permissions for a directory B.

mkruisselbrink commented 2 years ago

I don't think we're likely to add anything more than what can already be polyfilled on the existing implementation (i.e. you can keep track of parent yourself). showDirectoryPicker (and showFilePicker) does now have an option to start the directory out in a website provided directory, which should make it easier to get the user to select the parent directory of a file for example, and I don't think we'd want to add anything more than that.