A nice graphical filesystem explorer for viewing the ipfs files api.
I'm personally a fan of the windows 10 explorer UI:
I would argue its the most successful file explorer UI, and much of what makes windows user friendly and pleasant to use.
Notably, grid OR row layout, the 'location' bar up top, an 'up' button to go up a directory in the hierarchy. A 'quick bar' on the side might be nice, we may have some directories in the files api that are prefilled with things in the future.
Use the js-ipfs-api to interact with the go-ipfs daemon. The files api calls are all in here
Either through dragging a file in or otherwise adding a file to the explorer,
first make a call to 'ipfs.add()', grab the hash that is returned, and then
call 'ipfs.files.cp' with the first argument being /ipfs/$THAT_HASH
and the
second argument being the path within the filesystem of the explorer that the
new file will go (current directory/name_of_file_being_added).
It may be worth checking if the destination path exists before the operation
and if it does, either automatically rename the file something like
original_file_name (1).ext
or pop up a notice to the user asking them to
select a name for the file.
ipfs.add(stream, function (err, res) {
if (err) { /* oh jeeze */ }
api.files.cp([res[0].Hash, '/path/to/me'], (err) => {
if (err) { /* do the javascripts */ }
})
})
To create a directory, call ipfs.files.mkdir(absolute_path)
ipfs.files.mkdir('/path/to/dir', (err) => {
if (err) { /* oh jeeze */ }
})
To get the items in a directory, call ipfs.files.ls
with the l
option set
to true. In the output you'll get an array of directory entry objects with
names, types, and hashes. The type field is current 0
for a file, and 1
for a directory, more types may be added later for things like symlinks.
ipfs.files.ls('/path/to/list', (err, res) => {
if (err) { /* error */ }
res.Entries.forEach((e) => {
console.log(e)
})
})
To get information such as the size and hash of an item, call ipfs.files.stat
.
The hash can be used to create a 'share' link to any given item: 'https://ipfs.io/ipfs/$HASH'
ipfs.files.stat('/path/to/the/thing', (err, res) => {
if (err) { /* bad things */ }
console.log(res)
})
To get the contents of a file, call ipfs.files.read
.
api.files.read('/the/path/to/the/thing', function (err, stream) {
if (err) { }
console.log("A stream: ", stream)
})
!! For now, let's not support downloading of directories. The js-ipfs api
!! currently doesnt provide good support for downloading an archive of a directory
!! via ipfs.get
.
To remove a file, call ipfs.files.rm
, for a directory, pass the recursive=true
option.
Note that deleting an item from this view does not necessarily remove it from
the user's system. That only happens when ipfs.repo.gc
gets run. It may be
worthwhile to have a UI element (like a trash bin on windows) that contains
deleted files, and you can 'clean it out' which runs a gc.
To rename (or otherwise move) an item, call ipfs.files.mv
with the files current name, and its new name.
Note that renaming a file to have the same name as an already existing file
will delete the existing file (replacing it with the one being renamed).
// Rename 'foo' to 'bar'
api.files.mv(['/foo', '/bar'], (err) => {
if (err) { /* handle */ }
})
To implement the traditional 'right click+Copy, right click+Paste', the copy
option should call ipfs.files.stat
to get the items hash, and then paste
should run ipfs.files.cp
as in the 'Adding a file' operation.
// On Copy
api.files.stat('/path/to/the/thing', function (err, res) {
if (err) { /* bad things */ }
clipboardHash = res.Hash
})
// On Paste
api.files.cp('/ipfs/' + clipboardHash, (err) => {
if (err) { }
})
We have a short example tutorial for interacting with the files API on the command line here.
You'll probably want to put a few files in there manually to make working on the UI a little easier. That guide should cover it pretty well.
I wrote a very early version of this a long time ago: https://github.com/ipfs/file-browser (I'm not expecting this to be reused at all)
And more recently, @dignifiedquire worked on a version of this in react/redux: https://github.com/ipfs/webui/tree/5ef3c3edaf59964ef324fe22eb28adeb039875d7/app/scripts/components/files