bugfix (UI): If an operation failed, the UI were giving the impression

to do something - #33
This commit is contained in:
Mickael KERJEAN 2018-04-12 23:45:12 +10:00
parent 13a6fb0004
commit 5a913d44d1
4 changed files with 117 additions and 81 deletions

View file

@ -98,19 +98,22 @@ function handle_error_response(xhr, err){
return message; return message;
})(xhr.responseText); })(xhr.responseText);
if(xhr.status === 500){ if(navigator.onLine === false){
err({message: message || "Oups something went wrong with our servers"}) err({message: 'Connection Lost', code: "NO_INTERNET"});
}else if(xhr.status === 500){
err({message: message || "Oups something went wrong with our servers", code: "INTERNAL_SERVER_ERROR"});
}else if(xhr.status === 401){ }else if(xhr.status === 401){
if(location.pathname !== '/login'){ location.pathname = "/login"; } if(location.pathname !== '/login'){ location.pathname = "/login"; }
err({message: message || "Authentication error"}); err({message: message || "Authentication error", code: "Unauthorized"});
}else if(xhr.status === 403){ }else if(xhr.status === 403){
err({message: message || "You can\'t do that"}); err({message: message || "You can\'t do that", code: "Forbidden"});
}else if(xhr.status === 413){ }else if(xhr.status === 413){
err({message: message || "Payload too large"}); err({message: message || "Payload too large", code: "PAYLOAD_TOO_LARGE"});
}else if(navigator.onLine === false){ }else if(xhr.status === 502){
err({status: xhr.status, code: "CONNECTION_LOST", message: 'Connection Lost'}); err({message: message || "The destination is acting weird", code: "BAD_GATEWAY"});
}else if(xhr.status === 409){
err({message: message || "Oups you just ran into a conflict", code: "CONFLICT"});
}else{ }else{
err({status: xhr.status, message: xhr.responseText || 'Oups something went wrong'}); err({message: message || 'Oups something went wrong'});
} }
} }

View file

@ -46,8 +46,7 @@ class FileSystem{
return cache.get(cache.FILE_PATH, path, false).then((_files) => { return cache.get(cache.FILE_PATH, path, false).then((_files) => {
if(_files && _files.results){ if(_files && _files.results){
let _files_virtual_to_keep = _files.results.filter((file) => { let _files_virtual_to_keep = _files.results.filter((file) => {
return file.icon === 'loading' && return file.icon === 'loading';
(new Date()).getTime() - file._timestamp < 1000*60*60;
}); });
// update file results // update file results
for(let i=0; i<_files_virtual_to_keep.length; i++){ for(let i=0; i<_files_virtual_to_keep.length; i++){
@ -95,6 +94,10 @@ class FileSystem{
}else{ }else{
return this._replace(path, 'error'); return this._replace(path, 'error');
} }
})
.catch((err) => {
this._replace(path, 'error');
return Promise.reject(err);
}); });
} }
@ -135,7 +138,11 @@ class FileSystem{
return this._replace(path, 'loading') return this._replace(path, 'loading')
.then(() => cache.put(cache.FILE_CONTENT, path, file)) .then(() => cache.put(cache.FILE_CONTENT, path, file))
.then(() => http_post(url, formData, 'multipart')) .then(() => http_post(url, formData, 'multipart'))
.then((res)=> res.status === 'ok'? this._replace(path) : this._replace(path, 'error')); .then((res)=> res.status === 'ok'? this._replace(path) : this._replace(path, 'error'))
.catch((err) => {
this._replace(path, 'error');
return Promise.reject(err);
});
} }
mkdir(path){ mkdir(path){
@ -143,7 +150,11 @@ class FileSystem{
return this._add(path, 'loading') return this._add(path, 'loading')
.then(() => this._add(path, 'loading')) .then(() => this._add(path, 'loading'))
.then(() => http_get(url)) .then(() => http_get(url))
.then((res) => res.status === 'ok'? this._replace(path) : this._replace(path, 'error')); .then((res) => res.status === 'ok'? this._replace(path) : this._replace(path, 'error'))
.catch((err) => {
this._replace(path, 'error');
return Promise.reject(err);
});
} }
touch(path, file){ touch(path, file){
@ -159,7 +170,11 @@ class FileSystem{
return http_get(url); return http_get(url);
} }
}) })
.then((res) => res.status === 'ok'? this._replace(path) : this._replace(path, 'error')); .then((res) => res.status === 'ok'? this._replace(path) : this._replace(path, 'error'))
.catch((err) => {
this._replace(path, 'error');
return Promise.reject(err);
});
} }
mv(from, to){ mv(from, to){
@ -168,18 +183,23 @@ class FileSystem{
return ui_before_request(from, to) return ui_before_request(from, to)
.then(() => this._ls_from_cache(dirname(from))) .then(() => this._ls_from_cache(dirname(from)))
.then(() => this._ls_from_cache(dirname(to))) .then(() => this._ls_from_cache(dirname(to)))
.then(() => http_get(url) .then(() => http_get(url).then((res) => {
.then((res) => { if(res.status === 'ok'){
if(res.status === 'ok'){ return ui_when_success.call(this, from, to)
return ui_when_success.call(this, from, to) .then(() => this._ls_from_cache(dirname(from)))
.then(() => this._ls_from_cache(dirname(from))) .then(() => this._ls_from_cache(dirname(to)));
.then(() => this._ls_from_cache(dirname(to))); }else{
}else{ return ui_when_fail.call(this, from, to)
return ui_when_fail.call(this, from, to) .then(() => this._ls_from_cache(dirname(from)))
.then(() => this._ls_from_cache(dirname(from))) .then(() => this._ls_from_cache(dirname(to)));
.then(() => this._ls_from_cache(dirname(to))); }
} }))
})); .catch((err) => {
ui_when_fail.call(this, from, to)
.then(() => this._ls_from_cache(dirname(from)))
.then(() => this._ls_from_cache(dirname(to)));
return Promise.reject(err);
});
function ui_before_request(from, to){ function ui_before_request(from, to){
return update_from() return update_from()
@ -201,7 +221,6 @@ class FileSystem{
if(file.name === basename(from)){ if(file.name === basename(from)){
file.name = basename(to); file.name = basename(to);
file.icon = 'loading'; file.icon = 'loading';
file._timestamp = (new Date()).getTime();
_file = file; _file = file;
} }
return file; return file;
@ -232,7 +251,10 @@ class FileSystem{
.then((res_from) => { .then((res_from) => {
if(!res_from || !res_from.results) return Promise.reject(); if(!res_from || !res_from.results) return Promise.reject();
res_from.results = res_from.results.map((file) => { res_from.results = res_from.results.map((file) => {
if(file.name === basename(from)){ if(
(dirname(from) === dirname(to) && file.name === basename(to)) ||
(dirname(from) !== dirname(to) && file.name === basename(from))
){
file.icon = 'error'; file.icon = 'error';
} }
return file; return file;
@ -339,11 +361,9 @@ class FileSystem{
if(file.name === basename(path)){ if(file.name === basename(path)){
if(!icon){ if(!icon){
delete file.icon; delete file.icon;
delete file._timestamp;
} }
if(icon){ if(icon){
file.icon = icon; file.icon = icon;
file._timestamp = (new Date()).getTime();
} }
} }
return file; return file;
@ -360,8 +380,7 @@ class FileSystem{
if(!res) return Promise.resolve(); if(!res) return Promise.resolve();
let file = { let file = {
name: basename(path), name: basename(path),
type: /\/$/.test(path) ? 'directory' : 'file', type: /\/$/.test(path) ? 'directory' : 'file'
_timestamp: (new Date()).getTime()
}; };
if(icon) file.icon = icon; if(icon) file.icon = icon;
res.results.push(file); res.results.push(file);

View file

@ -18,16 +18,12 @@ app.use(function(req, res, next){
// list files // list files
app.get('/ls', function(req, res){ app.get('/ls', function(req, res){
let path = pathBuilder(req); const path = pathBuilder(req);
if(path){ if(path){
Files Files
.ls(path, req.cookies.auth) .ls(path, req.cookies.auth)
.then(function(results){ .then(function(results){ res.send({status: 'ok', results: results}); })
res.send({status: 'ok', results: results}); .catch(function(err){ errorHandler(res, err, 'cannot fetch files'); });
})
.catch(function(err){
res.send({status: 'error', message: err.message || 'cannot fetch files', trace: err});
});
}else{ }else{
res.send({status: 'error', message: 'unknown path'}); res.send({status: 'error', message: 'unknown path'});
} }
@ -35,7 +31,7 @@ app.get('/ls', function(req, res){
// get a file content // get a file content
app.get('/cat', function(req, res){ app.get('/cat', function(req, res){
let path = pathBuilder(req); const path = pathBuilder(req);
res.clearCookie("download"); res.clearCookie("download");
if(path){ if(path){
Files.cat(path, req.cookies.auth, res) Files.cat(path, req.cookies.auth, res)
@ -43,9 +39,7 @@ app.get('/cat', function(req, res){
res.set('Content-Type', mime.getMimeType(path)); res.set('Content-Type', mime.getMimeType(path));
stream.pipe(res); stream.pipe(res);
}) })
.catch(function(err){ .catch(function(err){ errorHandler(res, err, 'couldn\'t read the file'); });
res.send({status: 'error', message: err.message || 'couldn\t read the file', trace: err});
});
}else{ }else{
res.send({status: 'error', message: 'unknown path'}); res.send({status: 'error', message: 'unknown path'});
} }
@ -54,22 +48,20 @@ app.get('/cat', function(req, res){
// create/update a file // create/update a file
// https://github.com/pillarjs/multiparty // https://github.com/pillarjs/multiparty
app.post('/cat', function(req, res){ app.post('/cat', function(req, res){
var form = new multiparty.Form(), const form = new multiparty.Form(),
path = pathBuilder(req); path = pathBuilder(req);
if(path){ if(path){
form.on('part', function(part) { form.on('part', function(part) {
part.on('error', function(err){ part.on('error', function(err){
res.send({status: 'error', message: 'internal error'}); errorHandler(res, {code: "INTERNAL_ERROR", message: "internal error"}, 'internal error');
}); });
Files.write(path, part, req.cookies.auth) Files.write(path, part, req.cookies.auth)
.then(function(result){ .then(function(result){
res.send({status: 'ok'}); res.send({status: 'ok'});
}) })
.catch(function(err){ .catch(function(err){ errorHandler(res, err, 'couldn\'t write the file'); });
res.send({status: 'error', message: err.message || 'couldn\'t write the file', code: err.code});
});
}); });
form.parse(req); form.parse(req);
}else{ }else{
@ -79,19 +71,17 @@ app.post('/cat', function(req, res){
// rename a file/directory // rename a file/directory
app.get('/mv', function(req, res){ app.get('/mv', function(req, res){
let from = decodeURIComponent(req.query.from), req.query.path = req.query.from;
to = decodeURIComponent(req.query.to); const from = pathBuilder(req);
req.query.path = req.query.to;
const to = pathBuilder(req)
if(from === to){ if(from === to){
res.send({status: 'ok'}); res.send({status: 'ok'});
}else if(from && to){ }else if(from && to){
Files.mv(from, to, req.cookies.auth) Files.mv(from, to, req.cookies.auth)
.then((message) => { .then(function(message){ res.send({status: 'ok'}); })
res.send({status: 'ok'}); .catch(function(err){ errorHandler(res, err, 'couldn\'t rename your file'); });
})
.catch((err) => {
res.send({status: 'error', message: err.message || 'couldn\'t rename your file', trace: err});
});
}else{ }else{
res.send({status: 'error', message: 'unknown path'}); res.send({status: 'error', message: 'unknown path'});
} }
@ -99,15 +89,11 @@ app.get('/mv', function(req, res){
// delete a file/directory // delete a file/directory
app.get('/rm', function(req, res){ app.get('/rm', function(req, res){
let path = pathBuilder(req); const path = pathBuilder(req);
if(path){ if(path){
Files.rm(path, req.cookies.auth) Files.rm(path, req.cookies.auth)
.then((message) => { .then(function(message){ res.send({status: 'ok'}); })
res.send({status: 'ok'}); .catch(function(err){ errorHandler(res, err, 'couldn\'t delete your file'); });
})
.catch((err) => {
res.send({status: 'error', message: err.message || 'couldn\'t delete your file', trace: err});
});
}else{ }else{
res.send({status: 'error', message: 'unknown path'}); res.send({status: 'error', message: 'unknown path'});
} }
@ -115,30 +101,22 @@ app.get('/rm', function(req, res){
// create a directory // create a directory
app.get('/mkdir', function(req, res){ app.get('/mkdir', function(req, res){
let path = pathBuilder(req); const path = pathBuilder(req);
if(path){ if(path){
Files.mkdir(path, req.cookies.auth) Files.mkdir(path, req.cookies.auth)
.then((message) => { .then(function(message){ res.send({status: 'ok'}); })
res.send({status: 'ok'}); .catch(function(err){ errorHandler(res, err, 'couldn\'t create the directory'); });
})
.catch((err) => {
res.send({status: 'error', message: err.message || 'couldn\'t create a directory', trace: err});
});
}else{ }else{
res.send({status: 'error', message: 'unknown path'}); res.send({status: 'error', message: 'unknown path'});
} }
}); });
app.get('/touch', function(req, res){ app.get('/touch', function(req, res){
let path = pathBuilder(req); const path = pathBuilder(req);
if(path){ if(path){
Files.touch(path, req.cookies.auth) Files.touch(path, req.cookies.auth)
.then((message) => { .then(function(message){ res.send({status: 'ok'}); })
res.send({status: 'ok'}); .catch(function(err){ errorHandler(res, err, 'couldn\'t create the file'); });
})
.catch((err) => {
res.send({status: 'error', message: err.message || 'couldn\'t create a file', trace: err});
});
}else{ }else{
res.send({status: 'error', message: 'unknown path'}); res.send({status: 'error', message: 'unknown path'});
} }
@ -150,3 +128,39 @@ module.exports = app;
function pathBuilder(req){ function pathBuilder(req){
return path.join(req.cookies.auth.payload.path || '', decodeURIComponent(req.query.path) || ''); return path.join(req.cookies.auth.payload.path || '', decodeURIComponent(req.query.path) || '');
} }
function errorHandler(res, err, defaultMessage){
const code = {
"INTERNAL_ERROR": {message: "Oops, it seems we had a problem", status: 500},
"ECONNREFUSED": {message: "Oops, the service you are connected on is not available", status: 502}
};
const status = function(_code, _status){
if(code[_code]){
return code[_code]['status'];
}
_status = parseInt(_status);
if(_status >= 400 && _status < 600){
return _status;
}
return 404;
}(err.code || err.errno, err.status);
if(code[err.code || err.errno]){
res.status(status).send({
status: 'error',
message: code[err.code]['message']
});
}else if(err.message){
res.status(status).send({
status: 'error',
message: err.message || 'cannot fetch files',
trace: err
});
}else{
res.status(status).send({
status: 'error',
message: defaultMessage,
trace: err
});
}
}