mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2025-10-30 09:37:55 +08:00
feature (notification): proper notification system
This commit is contained in:
@ -1,15 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { NgIf } from './';
|
|
||||||
|
|
||||||
import "./error.scss";
|
|
||||||
|
|
||||||
export const Error = (props) => {
|
|
||||||
return (
|
|
||||||
<div className="component_error">
|
|
||||||
{props.err.message || "Oups something went wrong :/"}
|
|
||||||
<NgIf cond={props.err.trace !== undefined} className="trace">
|
|
||||||
{JSON.stringify(props.err.trace)}
|
|
||||||
</NgIf>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
.component_error{
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 50px;
|
|
||||||
font-size: 25px;
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 100;
|
|
||||||
|
|
||||||
.trace{
|
|
||||||
fontSize: 12px;
|
|
||||||
maxWidth: 500px;
|
|
||||||
margin: 10px auto 0 auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -7,7 +7,6 @@ export { Container } from './container';
|
|||||||
export { NgIf } from './ngif';
|
export { NgIf } from './ngif';
|
||||||
export { Card } from './card';
|
export { Card } from './card';
|
||||||
export { Loader } from './loader';
|
export { Loader } from './loader';
|
||||||
export { Error } from './error';
|
|
||||||
export { Fab } from './fab';
|
export { Fab } from './fab';
|
||||||
export { Icon } from './icon';
|
export { Icon } from './icon';
|
||||||
export { Uploader } from './uploader';
|
export { Uploader } from './uploader';
|
||||||
|
|||||||
@ -1,68 +1,107 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
|
||||||
|
|
||||||
import { NgIf } from './';
|
import { NgIf } from './';
|
||||||
|
import { notify } from '../helpers/';
|
||||||
import './notification.scss';
|
import './notification.scss';
|
||||||
|
|
||||||
export class Notification extends React.Component {
|
export class Notification extends React.Component {
|
||||||
constructor(props){
|
constructor(props){
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
visible: null,
|
appear: false,
|
||||||
error: null,
|
message_text: null,
|
||||||
timeout: null
|
message_type: null
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
componentWillMount(){
|
function TaskManager(){
|
||||||
this.componentWillReceiveProps(this.props);
|
let jobs = [];
|
||||||
}
|
let is_running = false;
|
||||||
|
|
||||||
componentWillUnmount(){
|
const ret = {
|
||||||
window.clearTimeout(this.timeout);
|
addJob: (job) => {
|
||||||
}
|
jobs.push(job);
|
||||||
|
if(is_running === false){
|
||||||
componentWillReceiveProps(props){
|
is_running = true;
|
||||||
if(props.error !== null){
|
ret._executor();
|
||||||
this.componentWillUnmount();
|
}
|
||||||
this.setState({visible: true, error: props.error});
|
},
|
||||||
this.timeout = window.setTimeout(() => {
|
_executor: () => {
|
||||||
this.setState({visible: null});
|
let job = jobs.shift();
|
||||||
}, 5000);
|
if(!job){
|
||||||
|
is_running = false;
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
return job().then(ret._executor);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
this.runner = new TaskManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleVisibility(){
|
componentDidMount(){
|
||||||
this.setState({visible: !this.state.visible});
|
notify.subscribe((_message, type) => {
|
||||||
}
|
let job = playMessage.bind(this, {
|
||||||
|
text: stringify(_message),
|
||||||
formatError(err){
|
type: type
|
||||||
if(typeof err === 'object'){
|
});
|
||||||
if(err && err.message){
|
this.runner.addJob(job);
|
||||||
return err.message;
|
});
|
||||||
}else{
|
function stringify(data){
|
||||||
return JSON.stringify(err);
|
if(typeof data === 'object' && data.message){
|
||||||
|
return data.message;
|
||||||
|
}else if(typeof data === 'string'){
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
}else if(typeof err === 'string'){
|
return JSON.stringify(data);
|
||||||
return err;
|
|
||||||
}else{
|
|
||||||
throw('unrecognized notification');
|
|
||||||
}
|
}
|
||||||
|
function playMessage(message){
|
||||||
|
const displayMessage = (message) => {
|
||||||
|
this.setState({
|
||||||
|
appear: true,
|
||||||
|
message_text: message.text,
|
||||||
|
message_type: message.type
|
||||||
|
});
|
||||||
|
return Promise.resolve(message);
|
||||||
|
};
|
||||||
|
const waitForABit = (timeout, message) => {
|
||||||
|
return new Promise((done, err) => {
|
||||||
|
window.setTimeout(() => {
|
||||||
|
done(message);
|
||||||
|
}, timeout);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const hideMessage = (message) => {
|
||||||
|
this.setState({
|
||||||
|
appear: false
|
||||||
|
});
|
||||||
|
return Promise.resolve(message);
|
||||||
|
};
|
||||||
|
|
||||||
|
return displayMessage(message)
|
||||||
|
.then(waitForABit.bind(this, 5000))
|
||||||
|
.then(hideMessage)
|
||||||
|
.then(waitForABit.bind(this, 1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(){
|
||||||
|
this.setState({ appear: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
render(){
|
render(){
|
||||||
return (
|
return (
|
||||||
<NgIf cond={this.state.visible === true}>
|
<NgIf cond={this.state.appear === true} className="component_notification no-select">
|
||||||
<div className="component_notification">
|
<ReactCSSTransitionGroup transitionName="notification" transitionLeave={true} transitionLeaveTimeout={200} transitionEnter={true} transitionEnterTimeout={500}>
|
||||||
<div onClick={this.toggleVisibility.bind(this)}>
|
<div className={"component_notification--container "+(this.state.message_type || 'info')}>
|
||||||
{this.formatError(this.state.error)}
|
<div className="message">
|
||||||
|
{ this.state.message_text }
|
||||||
|
</div>
|
||||||
|
<div className="close" onClick={this.close.bind(this)}>X</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ReactCSSTransitionGroup>
|
||||||
</NgIf>
|
</NgIf>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Notification.propTypes = {
|
|
||||||
error: PropTypes.any
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,22 +1,42 @@
|
|||||||
.component_notification{
|
.component_notification{
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 25px;
|
||||||
left: 0;
|
left: 25px;
|
||||||
right: 0;
|
right: 0;
|
||||||
text-align: center;
|
font-size: 0.95em;
|
||||||
|
|
||||||
|
.component_notification--container{
|
||||||
|
width: 400px;
|
||||||
|
|
||||||
> div{
|
|
||||||
display: inline-block;
|
|
||||||
background: #637d8b;
|
|
||||||
min-width: 200px;
|
|
||||||
max-width: 400px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 10px 15px;
|
|
||||||
border-top-left-radius: 3px;
|
|
||||||
border-top-right-radius: 3px;
|
|
||||||
color: white;
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
cursor: pointer;
|
display: inline-block;
|
||||||
box-shadow: rgba(0, 0, 0, 0.14) 0px 4px 5px 0px, rgba(0, 0, 0, 0.12) 0px 1px 10px 0px, rgba(0, 0, 0, 0.2) 0px 2px 4px -1px;
|
padding: 15px 25px 15px 15px;
|
||||||
|
border-radius: 2px;
|
||||||
|
box-shadow: rgba(0, 0, 0, 0.14) 0px 4px 5px 0px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&.info{
|
||||||
|
background: rgba(0,0,0,0.6);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
&.error{
|
||||||
|
background: var(--error);
|
||||||
|
color: var(--secondary);
|
||||||
|
}
|
||||||
|
&.success{
|
||||||
|
background: var(--success);
|
||||||
|
color: var(--secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.message{
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
.close{
|
||||||
|
color: rgba(0,0,0,0.3);
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0 2px;
|
||||||
|
font-size: 0.95em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,3 +10,4 @@ export { prepare } from './navigate';
|
|||||||
export { invalidate, http_get, http_post, http_delete } from './ajax';
|
export { invalidate, http_get, http_post, http_delete } from './ajax';
|
||||||
export { screenHeight } from './dom';
|
export { screenHeight } from './dom';
|
||||||
export { prompt } from './prompt';
|
export { prompt } from './prompt';
|
||||||
|
export { notify } from './notify';
|
||||||
|
|||||||
17
client/helpers/notify.js
Normal file
17
client/helpers/notify.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const Message = function (){
|
||||||
|
let fn = null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
send: function(text, type){
|
||||||
|
if(['info', 'success', 'error'].indexOf(type) === -1){ type = 'info'; }
|
||||||
|
if(!fn){ return window.setTimeout(() => this.send(text,type), 50); }
|
||||||
|
fn(text, type);
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
subscribe: function(_fn){
|
||||||
|
fn = _fn;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const notify = new Message();
|
||||||
@ -84,7 +84,7 @@ class FileSystem{
|
|||||||
|
|
||||||
rm(path){
|
rm(path){
|
||||||
const url = '/api/files/rm?path='+prepare(path);
|
const url = '/api/files/rm?path='+prepare(path);
|
||||||
this._replace(path, 'loading')
|
return this._replace(path, 'loading')
|
||||||
.then(() => http_get(url))
|
.then(() => http_get(url))
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if(res.status === 'ok'){
|
if(res.status === 'ok'){
|
||||||
@ -127,14 +127,14 @@ class FileSystem{
|
|||||||
|
|
||||||
mkdir(path){
|
mkdir(path){
|
||||||
const url = '/api/files/mkdir?path='+prepare(path);
|
const url = '/api/files/mkdir?path='+prepare(path);
|
||||||
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'));
|
||||||
}
|
}
|
||||||
|
|
||||||
touch(path, file){
|
touch(path, file){
|
||||||
this._add(path, 'loading')
|
return this._add(path, 'loading')
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if(file){
|
if(file){
|
||||||
const url = '/api/files/cat?path='+prepare(path);
|
const url = '/api/files/cat?path='+prepare(path);
|
||||||
@ -152,7 +152,7 @@ class FileSystem{
|
|||||||
mv(from, to){
|
mv(from, to){
|
||||||
const url = '/api/files/mv?from='+prepare(from)+"&to="+prepare(to);
|
const url = '/api/files/mv?from='+prepare(from)+"&to="+prepare(to);
|
||||||
|
|
||||||
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)
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import './connectpage.scss';
|
|||||||
import { Session } from '../model/';
|
import { Session } from '../model/';
|
||||||
import { Container, NgIf, Loader, Notification } from '../components/';
|
import { Container, NgIf, Loader, Notification } from '../components/';
|
||||||
import { ForkMe, RememberMe, Credentials, Form } from './connectpage/';
|
import { ForkMe, RememberMe, Credentials, Form } from './connectpage/';
|
||||||
import { cache } from '../helpers/';
|
import { cache, notify } from '../helpers/';
|
||||||
import config from '../../config_client';
|
import config from '../../config_client';
|
||||||
|
|
||||||
import { Alert } from '../components/';
|
import { Alert } from '../components/';
|
||||||
@ -17,7 +17,6 @@ export class ConnectPage extends React.Component {
|
|||||||
credentials: {},
|
credentials: {},
|
||||||
remember_me: window.localStorage.hasOwnProperty('credentials') ? true : false,
|
remember_me: window.localStorage.hasOwnProperty('credentials') ? true : false,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
|
||||||
doing_a_third_party_login: false
|
doing_a_third_party_login: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -52,9 +51,9 @@ export class ConnectPage extends React.Component {
|
|||||||
const path = params.path && /^\//.test(params.path)? /\/$/.test(params.path) ? params.path : params.path+'/' : '/';
|
const path = params.path && /^\//.test(params.path)? /\/$/.test(params.path) ? params.path : params.path+'/' : '/';
|
||||||
this.props.history.push('/files'+path);
|
this.props.history.push('/files'+path);
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch((err) => {
|
||||||
this.setState({loading: false, error: err});
|
this.setState({loading: false});
|
||||||
window.setTimeout(() => this.setState({error: null}), 1000);
|
notify.send(err, 'error');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,16 +63,16 @@ export class ConnectPage extends React.Component {
|
|||||||
Session.url('dropbox').then((url) => {
|
Session.url('dropbox').then((url) => {
|
||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
this.setState({loading: false, error: err});
|
this.setState({loading: false});
|
||||||
window.setTimeout(() => this.setState({error: null}), 1000);
|
notify.send(err, 'error');
|
||||||
});
|
});
|
||||||
}else if(source === 'google'){
|
}else if(source === 'google'){
|
||||||
this.setState({loading: true});
|
this.setState({loading: true});
|
||||||
Session.url('gdrive').then((url) => {
|
Session.url('gdrive').then((url) => {
|
||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
this.setState({loading: false, error: err});
|
this.setState({loading: false});
|
||||||
window.setTimeout(() => this.setState({error: null}), 1000);
|
notify.send(err, 'error');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,7 +117,6 @@ export class ConnectPage extends React.Component {
|
|||||||
onCredentialsFound={this.setCredentials.bind(this)}
|
onCredentialsFound={this.setCredentials.bind(this)}
|
||||||
credentials={this.state.credentials} />
|
credentials={this.state.credentials} />
|
||||||
</NgIf>
|
</NgIf>
|
||||||
<Notification error={this.state.error && this.state.error.message} />
|
|
||||||
</Container>
|
</Container>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -6,8 +6,8 @@ import Path from 'path';
|
|||||||
|
|
||||||
import './filespage.scss';
|
import './filespage.scss';
|
||||||
import { Files } from '../model/';
|
import { Files } from '../model/';
|
||||||
import { NgIf, Loader, Error, Uploader, EventReceiver } from '../components/';
|
import { NgIf, Loader, Uploader, EventReceiver } from '../components/';
|
||||||
import { debounce, goToFiles, goToViewer, event, screenHeight } from '../helpers/';
|
import { notify, debounce, goToFiles, goToViewer, event, screenHeight } from '../helpers/';
|
||||||
import { BreadCrumb, FileSystem } from './filespage/';
|
import { BreadCrumb, FileSystem } from './filespage/';
|
||||||
|
|
||||||
@EventReceiver
|
@EventReceiver
|
||||||
@ -81,6 +81,7 @@ export class FilesPage extends React.Component {
|
|||||||
});
|
});
|
||||||
this.setState({files: files, loading: false});
|
this.setState({files: files, loading: false});
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
|
notify.send(error, 'error');
|
||||||
this.setState({error: error});
|
this.setState({error: error});
|
||||||
});
|
});
|
||||||
this.setState({error: false});
|
this.setState({error: false});
|
||||||
@ -88,18 +89,26 @@ export class FilesPage extends React.Component {
|
|||||||
|
|
||||||
onCreate(path, type, file){
|
onCreate(path, type, file){
|
||||||
if(type === 'file'){
|
if(type === 'file'){
|
||||||
return Files.touch(path, file);
|
return Files.touch(path, file)
|
||||||
|
.then(() => notify.send('A file named "'+Path.basename(path)+'" was created', 'success'))
|
||||||
|
.catch((err) => notify.send(err, 'error'));
|
||||||
}else if(type === 'directory'){
|
}else if(type === 'directory'){
|
||||||
return Files.mkdir(path);
|
return Files.mkdir(path)
|
||||||
|
.then(() => notify.send('A folder named "'+Path.basename(path)+'" was created', 'success'))
|
||||||
|
.catch((err) => notify.send(err, 'error'));
|
||||||
}else{
|
}else{
|
||||||
return Promise.reject({message: 'internal error: can\'t create a '+type.toString(), code: 'UNKNOWN_TYPE'});
|
return Promise.reject({message: 'internal error: can\'t create a '+type.toString(), code: 'UNKNOWN_TYPE'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onRename(from, to, type){
|
onRename(from, to, type){
|
||||||
return Files.mv(from, to, type);
|
return Files.mv(from, to, type)
|
||||||
|
.then(() => notify.send('The file "'+Path.basename(from)+'" was renamed', 'success'))
|
||||||
|
.catch((err) => notify.send(err, 'error'));
|
||||||
}
|
}
|
||||||
onDelete(file, type){
|
onDelete(path, type){
|
||||||
return Files.rm(file, type);
|
return Files.rm(path, type)
|
||||||
|
.then(() => notify.send('The file "'+Path.basename(path)+'" was deleted', 'success'))
|
||||||
|
.catch((err) => notify.send(err, 'error'));
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpload(path, files){
|
onUpload(path, files){
|
||||||
@ -205,10 +214,7 @@ export class FilesPage extends React.Component {
|
|||||||
<FileSystem path={this.state.path} files={this.state.files} />
|
<FileSystem path={this.state.path} files={this.state.files} />
|
||||||
<Uploader path={this.state.path} />
|
<Uploader path={this.state.path} />
|
||||||
</NgIf>
|
</NgIf>
|
||||||
<NgIf cond={!!this.state.error} className="error" onClick={this.componentDidMount.bind(this)}>
|
<NgIf cond={this.state.loading}>
|
||||||
<Error err={this.state.error}/>
|
|
||||||
</NgIf>
|
|
||||||
<NgIf cond={this.state.loading && !this.state.error}>
|
|
||||||
<Loader/>
|
<Loader/>
|
||||||
</NgIf>
|
</NgIf>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -85,20 +85,14 @@ export class ExistingThing extends React.Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelect(){
|
|
||||||
if(this.state.icon !== 'loading' && this.state.icon !== 'error'){
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onRename(newFilename){
|
onRename(newFilename){
|
||||||
if(this.state.icon !== 'loading' && this.state.icon !== 'error'){
|
this.props.emit(
|
||||||
this.props.emit(
|
'file.rename',
|
||||||
'file.rename',
|
pathBuilder(this.props.path, this.props.file.name),
|
||||||
pathBuilder(this.props.path, this.props.file.name),
|
pathBuilder(this.props.path, newFilename),
|
||||||
pathBuilder(this.props.path, newFilename),
|
this.props.file.type
|
||||||
this.props.file.type
|
);
|
||||||
);
|
this.setState({is_renaming: false});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRenameRequest(){
|
onRenameRequest(){
|
||||||
|
|||||||
@ -2,8 +2,8 @@ import React from 'react';
|
|||||||
import Path from 'path';
|
import Path from 'path';
|
||||||
|
|
||||||
import { Files } from '../model/';
|
import { Files } from '../model/';
|
||||||
import { BreadCrumb, Bundle, NgIf, Loader, Error, Container, EventReceiver, EventEmitter } from '../components/';
|
import { BreadCrumb, Bundle, NgIf, Loader, Container, EventReceiver, EventEmitter } from '../components/';
|
||||||
import { debounce, opener, screenHeight } from '../helpers/';
|
import { debounce, opener, screenHeight, notify } from '../helpers/';
|
||||||
import { AudioPlayer, FileDownloader, ImageViewer, PDFViewer } from './viewerpage/';
|
import { AudioPlayer, FileDownloader, ImageViewer, PDFViewer } from './viewerpage/';
|
||||||
|
|
||||||
const VideoPlayer = (props) => (
|
const VideoPlayer = (props) => (
|
||||||
@ -29,7 +29,6 @@ export class ViewerPage extends React.Component {
|
|||||||
needSaving: false,
|
needSaving: false,
|
||||||
isSaving: false,
|
isSaving: false,
|
||||||
loading: true,
|
loading: true,
|
||||||
error: false,
|
|
||||||
height: 0
|
height: 0
|
||||||
};
|
};
|
||||||
this.props.subscribe('file.select', this.onPathUpdate.bind(this));
|
this.props.subscribe('file.select', this.onPathUpdate.bind(this));
|
||||||
@ -37,7 +36,7 @@ export class ViewerPage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount(){
|
componentWillMount(){
|
||||||
this.setState({loading: null, error: false}, () => {
|
this.setState({loading: null}, () => {
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
if(this.state.loading === null) this.setState({loading: true});
|
if(this.state.loading === null) this.setState({loading: true});
|
||||||
}, 500);
|
}, 500);
|
||||||
@ -50,13 +49,12 @@ export class ViewerPage extends React.Component {
|
|||||||
if(err && err.code === 'CANCELLED'){ return; }
|
if(err && err.code === 'CANCELLED'){ return; }
|
||||||
if(err.code === 'BINARY_FILE'){
|
if(err.code === 'BINARY_FILE'){
|
||||||
Files.url(this.state.path).then((url) => {
|
Files.url(this.state.path).then((url) => {
|
||||||
console.log(this.state.path);
|
|
||||||
this.setState({data: url, loading: false, opener: 'download'});
|
this.setState({data: url, loading: false, opener: 'download'});
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
this.setState({error: err});
|
notify.send(err, 'error');
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
this.setState({error: err});
|
notify.send(err, 'error');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
@ -64,7 +62,7 @@ export class ViewerPage extends React.Component {
|
|||||||
this.setState({data: url, loading: false, opener: app});
|
this.setState({data: url, loading: false, opener: app});
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
if(err && err.code === 'CANCELLED'){ return; }
|
if(err && err.code === 'CANCELLED'){ return; }
|
||||||
this.setState({error: err});
|
notify.send(err, 'error');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,13 +85,10 @@ export class ViewerPage extends React.Component {
|
|||||||
this.setState({needSaving: false});
|
this.setState({needSaving: false});
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
if(err && err.code === 'CANCELLED'){ return; }
|
if(err && err.code === 'CANCELLED'){
|
||||||
this.setState({isSaving: false});
|
notify.send(err, 'error');
|
||||||
let message = "Oups, something went wrong";
|
|
||||||
if(err.message){
|
|
||||||
message += ':\n'+err.message;
|
|
||||||
}
|
}
|
||||||
alert(message);
|
this.setState({isSaving: false});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,12 +137,7 @@ export class ViewerPage extends React.Component {
|
|||||||
</NgIf>
|
</NgIf>
|
||||||
</NgIf>
|
</NgIf>
|
||||||
<NgIf cond={this.state.loading === true}>
|
<NgIf cond={this.state.loading === true}>
|
||||||
<NgIf cond={this.state.error === false}>
|
<Loader/>
|
||||||
<Loader/>
|
|
||||||
</NgIf>
|
|
||||||
<NgIf cond={this.state.error !== false} onClick={this.componentWillMount.bind(this)} style={{cursor: 'pointer'}}>
|
|
||||||
<Error err={this.state.error}/>
|
|
||||||
</NgIf>
|
|
||||||
</NgIf>
|
</NgIf>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -21,6 +21,7 @@ export default class AppRouter extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
<ModalPrompt />
|
<ModalPrompt />
|
||||||
|
<Notification />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -80,7 +80,10 @@ app.post('/cat', function(req, res){
|
|||||||
app.get('/mv', function(req, res){
|
app.get('/mv', function(req, res){
|
||||||
let from = decodeURIComponent(req.query.from),
|
let from = decodeURIComponent(req.query.from),
|
||||||
to = decodeURIComponent(req.query.to);
|
to = decodeURIComponent(req.query.to);
|
||||||
if(from && to){
|
|
||||||
|
if(from === to){
|
||||||
|
res.send({status: 'ok'});
|
||||||
|
}else if(from && to){
|
||||||
Files.mv(from, to, req.cookies.auth)
|
Files.mv(from, to, req.cookies.auth)
|
||||||
.then((message) => {
|
.then((message) => {
|
||||||
res.send({status: 'ok'});
|
res.send({status: 'ok'});
|
||||||
|
|||||||
Reference in New Issue
Block a user