Skip to content

Commit

Permalink
Add progress bar for upload + cancel
Browse files Browse the repository at this point in the history
  • Loading branch information
rvazarkar committed Aug 24, 2016
1 parent df982a1 commit 1e280ea
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 13 deletions.
2 changes: 2 additions & 0 deletions src/AppContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import GraphContainer from './components/Graph';
import SearchContainer from './components/SearchContainer/SearchContainer';
import SpotlightContainer from './components/Spotlight/SpotlightContainer';
import LogoutModal from './components/Modals/LogoutModal';
import CancelUploadModal from './components/Modals/CancelUploadModal';
import ClearWarnModal from './components/Modals/ClearWarnModal'
import ClearConfirmModal from './components/Modals/ClearConfirmModal'
import ClearingModal from './components/Modals/ClearingModal'
Expand Down Expand Up @@ -39,6 +40,7 @@ export default class AppContainer extends Component {
<ClearWarnModal />
<ClearConfirmModal />
<ClearingModal />
<CancelUploadModal />
<RawQuery />
<MenuContainer />
<Settings />
Expand Down
74 changes: 61 additions & 13 deletions src/components/Menu/MenuContainer.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { Component } from 'react';
import MenuButton from './MenuButton';
import ProgressBarMenuButton from './ProgressBarMenuButton';
import { buildMergeQuery, defaultAjaxSettings } from 'utils';
import { If, Then, Else } from 'react-if';
const { dialog } = require('electron').remote
var fs = require('fs')

Expand All @@ -9,8 +11,22 @@ export default class MenuContainer extends Component {
super()

this.state = {
refreshHover: false
refreshHover: false,
uploading: false,
progress: 0,
parser: null,
currentAjax: null
}

emitter.on('cancelUpload', this.cancelUpload.bind(this))
}

cancelUpload(){
this.state.parser.abort()
this.state.currentAjax.abort()
setTimeout(function(){
this.setState({uploading: false})
}.bind(this), 1000)
}

_refreshClick(){
Expand Down Expand Up @@ -44,7 +60,10 @@ export default class MenuContainer extends Component {
properties: ['openFile']
})[0]

var i;

fs.readFile(filename, 'utf8', function(err, data){
var count = data.split('\n').length;
var header = data.split('\n')[0]
var filetype;
if (header.includes('UserName') && header.includes('ComputerName') && header.includes('Weight')){
Expand All @@ -62,31 +81,53 @@ export default class MenuContainer extends Component {
return;
}

this.setState({
uploading: true,
progress: 0
})
var completed = -1;
Papa.parse(data,{
worker: true,
header: true,
dynamicTyping: true,
chunkSize: 131072,
chunk: function(rows, parser){
parser.pause()
this.setState({parser: parser})
var options = defaultAjaxSettings()
options.url = appStore.databaseInfo.url + '/db/data/batch'
var data = JSON.stringify(buildMergeQuery(rows.data, filetype), null, 2)
//var data = JSON.stringify(buildMergeQuery(rows.data, filetype), null, 2)
options.data = JSON.stringify(buildMergeQuery(rows.data, filetype))
options.complete = function(){
options.success = function(){
completed += rows.data.length
this.setState({progress: Math.floor((completed / count) * 100)})
if (completed === count){
setTimeout(function(){
this.setState({uploading: false})
}.bind(this), 3000)
}
parser.resume()
emitter.emit('refreshDBData')
}
}.bind(this)
options.error = function(xhr, status, error){
console.log(xhr)
console.log(status)
console.log(error)
if (xhr.statusText !== 'abort'){
console.log(xhr)
console.log(status)
console.log(error)
}
}
$.ajax(options);
}
var a = $.ajax(options);
this.setState({currentAjax: a})
}.bind(this)
})
})
}.bind(this))
}

_settingsClick(){
emitter.emit('openSettings')
emitter.emit('openSettings')
}

_cancelUploadClick(){
emitter.emit('showCancelUpload')
}

render() {
Expand All @@ -102,7 +143,14 @@ export default class MenuContainer extends Component {
<MenuButton click={this._importClick.bind(this)} hoverVal="Import Graph" glyphicon="glyphicon glyphicon-import" />
</div>
<div>
<MenuButton click={this._uploadClick.bind(this)} hoverVal="Upload Data" glyphicon="glyphicon glyphicon-upload" />
<If condition={this.state.uploading}>
<Then>
<ProgressBarMenuButton click={this._cancelUploadClick.bind(this)} progress={this.state.progress}/>
</Then>
<Else>{ () =>
<MenuButton click={this._uploadClick.bind(this)} hoverVal="Upload Data" glyphicon="glyphicon glyphicon-upload" />
}</Else>
</If>
</div>
<div>
<MenuButton click={this._changeLayoutClick.bind(this)} hoverVal="Change Layout Type" glyphicon="fa fa-line-chart" />
Expand Down
70 changes: 70 additions & 0 deletions src/components/Menu/ProgressBarMenuButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React, { Component } from 'react';

export default class ProgressBarMenuButton extends Component {
propTypes: {
progress : React.PropTypes.number.isRequired,
click : React.PropTypes.func.isRequired
}

constructor(){
super()

this.state = {
expanded: false
}
}

_leave(e){
this.setState({expanded: false})
var target = $(e.target)
var oldWidth = target.width()
target.html('{}%'.format(this.props.progress))
target.animate({
width: '41px'
}, 100)
}

_enter(e){
this.setState({expanded: true})
var target = $(e.target)
var oldWidth = target.width()
var template = `<div class="progress" style="margin-bottom:0px">
<div class="progress-bar progress-bar-striped active" role="progressbar" aria-value-now={} aria-value-max="100" style="width:{}%">
{}%
</div></div>`.formatAll(this.props.progress)
target.html(template)
target.animate({
width: '150px'
}, 100)
}

componentWillReceiveProps(nextProps){
if (this.state.expanded){
var template = `<div class="progress" style="margin-bottom:0px">
<div class="progress-bar progress-bar-striped active" role="progressbar" aria-value-now={} aria-value-max="100" style="width:{}%">
{}%
</div></div>`.formatAll(nextProps.progress)
$(this.refs.btn).html(template)
}else{
$(this.refs.btn).html('{}%'.format(nextProps.progress))
}

this.forceUpdate()
}

shouldComponentUpdate(nextProps, nextState){
return true
}

componentDidMount(){
$(this.refs.btn).html('{}%'.format(this.props.progress))
$(this.refs.btn).css('padding','6px 0px 6px 0px')
$(this.refs.btn).css('width','41px')
}

render() {
return (
<button ref="btn" onClick={this.props.click} onMouseLeave={this._leave.bind(this)} onMouseEnter={this._enter.bind(this)} className="btn" />
);
}
}
57 changes: 57 additions & 0 deletions src/components/Modals/CancelUploadModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { Component } from 'react';

var Modal = require('react-bootstrap').Modal;

export default class CancelUploadModal extends Component {

constructor(){
super();
this.state = {
open: false
}
}

closeModal(){
this.setState({ open: false })
}

closeAndCancel(){
this.setState({ open: false })
emitter.emit('cancelUpload');
}

openModal(){
this.setState({open: true})
}

componentDidMount() {
emitter.on('showCancelUpload', this.openModal.bind(this))
}

render() {
return (
<Modal
show={this.state.open}
onHide={this.closeModal}
aria-labelledby="CanceulUploadHeader">

<Modal.Header closeButton={true}>
<Modal.Title id="CancelUploadHeader">Cancel Upload</Modal.Title>
</Modal.Header>

<Modal.Body>
<p>Are you sure you want to cancel the upload?</p>
</Modal.Body>

<Modal.Footer>
<button type="button" className="btn btn-danger" onClick={this.closeAndCancel.bind(this)}>
Stop Upload
</button>
<button type="button" className="btn btn-primary" onClick={this.closeModal.bind(this)}>
Cancel
</button>
</Modal.Footer>
</Modal>
);
}
}

0 comments on commit 1e280ea

Please sign in to comment.