mirror of
https://github.com/mickael-kerjean/filestash
synced 2025-12-06 08:22:24 +01:00
improvement (dragdrop): Improve UI while doing a folder upload - #14
This commit is contained in:
parent
d6f7ad34f2
commit
e31cbc13e9
2 changed files with 122 additions and 40 deletions
|
|
@ -148,7 +148,6 @@ class FileSystem{
|
|||
}).then((response) => Promise.resolve(response.result));
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("ERROR");
|
||||
if(err.code === 'BINARY_FILE') return Promise.reject(err);
|
||||
|
||||
return cache.update(cache.FILE_CONTENT, path, (response) => {
|
||||
|
|
@ -175,12 +174,12 @@ class FileSystem{
|
|||
.then(() => {
|
||||
return this._saveFileToCache(path, file)
|
||||
.then(() => this._replace(path, null, 'loading'))
|
||||
.then(() => this._refresh(path))
|
||||
.then(() => this._refresh(path));
|
||||
})
|
||||
.catch((err) => {
|
||||
return this._replace(path, 'error', 'loading')
|
||||
.then(() => this._refresh(path))
|
||||
.then(() => Promise.reject(err))
|
||||
.then(() => Promise.reject(err));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -189,13 +188,31 @@ class FileSystem{
|
|||
origin_path = pathBuilder(this.current_path, basename(path), 'directoy'),
|
||||
destination_path = path;
|
||||
|
||||
const action_prepare = () => {
|
||||
const action_prepare = (part_of_a_batch_operation = false) => {
|
||||
if(part_of_a_batch_operation === true){
|
||||
return this._add(destination_path, 'loading')
|
||||
.then(() => this._refresh(destination_path));
|
||||
}
|
||||
|
||||
return this._add(destination_path, 'loading')
|
||||
.then(() => origin_path !== destination_path ? this._add(origin_path, 'loading') : Promise.resolve())
|
||||
.then(() => this._refresh(origin_path, destination_path))
|
||||
.then(() => this._refresh(origin_path, destination_path));
|
||||
};
|
||||
|
||||
const action_execute = () => {
|
||||
const action_execute = (part_of_a_batch_operation = false) => {
|
||||
if(part_of_a_batch_operation === true){
|
||||
return http_get(url)
|
||||
.then(() => {
|
||||
return this._replace(destination_path, null, 'loading')
|
||||
.then(() => this._refresh(destination_path));
|
||||
})
|
||||
.catch((err) => {
|
||||
this._replace(destination_path, 'error', 'loading')
|
||||
.then(() => this._refresh(origin_path, destination_path));
|
||||
return Promise.reject(err);
|
||||
});
|
||||
}
|
||||
|
||||
return http_get(url)
|
||||
.then(() => {
|
||||
return this._replace(destination_path, null, 'loading')
|
||||
|
|
@ -219,9 +236,9 @@ class FileSystem{
|
|||
|
||||
|
||||
if(step === 'prepare_only'){
|
||||
return action_prepare()
|
||||
return action_prepare(true);
|
||||
}else if(step === 'execute_only'){
|
||||
return action_execute();
|
||||
return action_execute(true);
|
||||
}else{
|
||||
return action_prepare().then(action_execute);
|
||||
}
|
||||
|
|
@ -231,18 +248,35 @@ class FileSystem{
|
|||
const origin_path = pathBuilder(this.current_path, basename(path), 'file'),
|
||||
destination_path = path;
|
||||
|
||||
const action_prepare = () => {
|
||||
return this._add(destination_path, 'loading')
|
||||
.then(() => origin_path !== destination_path ? this._add(origin_path, 'loading') : Promise.resolve())
|
||||
.then(() => this._refresh(origin_path, destination_path))
|
||||
const action_prepare = (part_of_a_batch_operation = false) => {
|
||||
if(part_of_a_batch_operation === true){
|
||||
return this._add(destination_path, 'loading')
|
||||
.then(() => this._refresh(destination_path));
|
||||
}else{
|
||||
return this._add(destination_path, 'loading')
|
||||
.then(() => origin_path !== destination_path ? this._add(origin_path, 'loading') : Promise.resolve())
|
||||
.then(() => this._refresh(origin_path, destination_path));
|
||||
}
|
||||
};
|
||||
const action_execute = () => {
|
||||
const action_execute = (part_of_a_batch_operation = false) => {
|
||||
if(part_of_a_batch_operation === true){
|
||||
return query()
|
||||
.then(() => {
|
||||
return this._replace(destination_path, null, 'loading')
|
||||
.then(() => this._refresh(destination_path));
|
||||
})
|
||||
.catch((err) => {
|
||||
this._replace(destination_path, null, 'error')
|
||||
.then(() => this._refresh(destination_path));
|
||||
return Promise.reject(err);
|
||||
});
|
||||
}
|
||||
return query()
|
||||
.then(() => {
|
||||
this._saveFileToCache(path, file)
|
||||
return this._saveFileToCache(path, file)
|
||||
.then(() => this._replace(destination_path, null, 'loading'))
|
||||
.then(() => origin_path !== destination_path ? this._remove(origin_path, 'loading') : Promise.resolve())
|
||||
.then(() => this._refresh(origin_path, destination_path))
|
||||
.then(() => this._refresh(origin_path, destination_path));
|
||||
})
|
||||
.catch((err) => {
|
||||
this._replace(origin_path, 'error', 'loading')
|
||||
|
|
@ -265,9 +299,9 @@ class FileSystem{
|
|||
};
|
||||
|
||||
if(step === 'prepare_only'){
|
||||
return action_prepare()
|
||||
return action_prepare(true);
|
||||
}else if(step === 'execute_only'){
|
||||
return action_execute();
|
||||
return action_execute(true);
|
||||
}else{
|
||||
return action_prepare().then(action_execute);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,11 +109,11 @@ export class FilesPage extends React.Component {
|
|||
if(type === 'file'){
|
||||
return Files.touch(path, file)
|
||||
.then(() => {
|
||||
notify.send('A file named "'+Path.basename(path)+'" was created', 'success')
|
||||
notify.send('A file named "'+Path.basename(path)+'" was created', 'success');
|
||||
return Promise.resolve();
|
||||
})
|
||||
.catch((err) => {
|
||||
notify.send(err, 'error')
|
||||
notify.send(err, 'error');
|
||||
return Promise.reject(err);
|
||||
});
|
||||
}else if(type === 'directory'){
|
||||
|
|
@ -136,49 +136,95 @@ export class FilesPage extends React.Component {
|
|||
}
|
||||
|
||||
onUpload(path, e){
|
||||
const MAX_POOL_SIZE = 2;
|
||||
const MAX_POOL_SIZE = 10;
|
||||
let PRIOR_STATUS = {};
|
||||
extract_upload_directory_the_way_that_works_but_non_official(e.dataTransfer.items || [], [])
|
||||
.then((files) => {
|
||||
if(files.length === 0){
|
||||
return extract_upload_crappy_hack_but_official_way(e.dataTransfer);
|
||||
}
|
||||
return Promise.resolve(files)
|
||||
})
|
||||
.then((files) => {
|
||||
return Promise.resolve(files.sort((a,b) => {
|
||||
return a.type !== b.type && a.type === 'file' ? 1 : -1;
|
||||
}));
|
||||
return Promise.resolve(files);
|
||||
})
|
||||
.then((files) => {
|
||||
const processes = files.map((file) => {
|
||||
file.path = Path.join(path, file.path);
|
||||
if(file.type === 'file'){
|
||||
Files.touch(file.path, file.file, 'prepare_only');
|
||||
return Files.touch.bind(Files, file.path, file.file, 'execute_only');
|
||||
return {
|
||||
parent: file._prior || null,
|
||||
fn: Files.touch.bind(Files, file.path, file.file, 'execute_only')
|
||||
};
|
||||
}else{
|
||||
Files.mkdir(file.path, 'prepare_only');
|
||||
return Files.mkdir.bind(Files, file.path, 'execute_only');
|
||||
return {
|
||||
id: file._id || null,
|
||||
parent: file._prior || null,
|
||||
fn: Files.mkdir.bind(Files, file.path, 'execute_only')
|
||||
};
|
||||
}
|
||||
});
|
||||
function runner(id){
|
||||
let current_process = null;
|
||||
if(processes.length === 0) return Promise.resolve();
|
||||
return processes.shift()(id)
|
||||
.then(() => runner(id));
|
||||
|
||||
for(let i=0; i<processes.length; i++){
|
||||
if(processes[i].parent === null || PRIOR_STATUS[processes[i].parent] === true){
|
||||
current_process = processes[i];
|
||||
processes.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(current_process){
|
||||
return current_process.fn(id)
|
||||
.then(() => {
|
||||
if(current_process.id) PRIOR_STATUS[current_process.id] = true;
|
||||
return runner(id);
|
||||
})
|
||||
.catch((err) => {
|
||||
notify.send(err, 'error');
|
||||
return runner(id);
|
||||
});
|
||||
}else{
|
||||
return waitABit()
|
||||
.then(() => runner(id));
|
||||
function waitABit(){
|
||||
return new Promise((done) => {
|
||||
window.setTimeout(() => {
|
||||
requestAnimationFrame(() => {
|
||||
done();
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Promise.all(Array.apply(null, Array(MAX_POOL_SIZE)).map((process,index) => {
|
||||
return runner();
|
||||
})).then(() => {
|
||||
notify.send('Upload completed', 'success')
|
||||
notify.send('Upload completed', 'success');
|
||||
}).catch((err) => {
|
||||
notify.send(err, 'error')
|
||||
notify.send(err, 'error');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
// adapted from: https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
|
||||
function _rand_id(){
|
||||
function s4() {
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
}
|
||||
return s4() + s4() + s4() + s4();
|
||||
}
|
||||
|
||||
function extract_upload_directory_the_way_that_works_but_non_official(items, files = []){
|
||||
const traverseDirectory = (item, _files) => {
|
||||
const traverseDirectory = (item, _files, parent_id) => {
|
||||
let file = {
|
||||
path: item.fullPath,
|
||||
path: item.fullPath
|
||||
};
|
||||
if(item.isFile){
|
||||
return new Promise((done, err) => {
|
||||
|
|
@ -186,6 +232,7 @@ export class FilesPage extends React.Component {
|
|||
item.file((_file, _err) => {
|
||||
if(!_err){
|
||||
file.file = _file;
|
||||
if(parent_id) file._prior = parent_id;
|
||||
_files.push(file);
|
||||
}
|
||||
done(_files);
|
||||
|
|
@ -194,19 +241,21 @@ export class FilesPage extends React.Component {
|
|||
}else if(item.isDirectory){
|
||||
file.type = "directory";
|
||||
file.path += "/";
|
||||
file._id = _rand_id();
|
||||
if(parent_id) file._prior = parent_id;
|
||||
_files.push(file);
|
||||
|
||||
return new Promise((done, err) => {
|
||||
item.createReader().readEntries(function(entries){
|
||||
Promise.all(entries.map((entry) => {
|
||||
return traverseDirectory(entry, _files)
|
||||
return traverseDirectory(entry, _files, file._id);
|
||||
})).then(() => done(_files));
|
||||
});
|
||||
});
|
||||
}else{
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
return Promise.all(
|
||||
Array.prototype.slice.call(items).map((item) => {
|
||||
if(typeof item.webkitGetAsEntry === 'function'){
|
||||
|
|
@ -231,13 +280,13 @@ export class FilesPage extends React.Component {
|
|||
return Promise.resolve('file');
|
||||
}
|
||||
return new Promise((done, err) => {
|
||||
let reader = new FileReader();
|
||||
let reader = new window.FileReader();
|
||||
reader.onload = function() {
|
||||
done('file');
|
||||
};
|
||||
reader.onerror = function() {
|
||||
done('directory');
|
||||
}
|
||||
};
|
||||
reader.readAsText(_f);
|
||||
});
|
||||
}
|
||||
|
|
@ -252,8 +301,7 @@ export class FilesPage extends React.Component {
|
|||
}else{
|
||||
file.path += "/";
|
||||
}
|
||||
files.push(file);
|
||||
return Promise.resolve();
|
||||
return Promise.resolve(file);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue