From: Joseph Coffland Date: Tue, 4 Dec 2018 23:09:25 +0000 (-0800) Subject: Added button to download current GCode file, fixed file handling problems X-Git-Url: https://git.buildbotics.com/?a=commitdiff_plain;h=e8ee57b61aa497594c7668a1cb80315af21ccd4a;p=bbctrl-firmware Added button to download current GCode file, fixed file handling problems --- diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a3ad26..69c3ff5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Buildbotics CNC Controller Firmware Changelog - Show simulation progress with or with out 3D view. - Synchronize file list between browsers. - Increased max simulation time to 24hrs. + - Added button to download current GCode file. ## v0.4.2 - Suppress ``Auto-creating missing tool`` warning. diff --git a/src/js/app.js b/src/js/app.js index c8f4e5e..8ba50dc 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -48,6 +48,14 @@ function compare_versions(a, b) { function is_object(o) {return o !== null && typeof o == 'object'} +function is_array(o) {return Array.isArray(o)} + + +function update_array(dst, src) { + while (dst.length) dst.pop() + for (var i = 0; i < src.length; i++) + Vue.set(dst, i, src[i]); +} function update_object(dst, src, remove) { @@ -68,7 +76,10 @@ function update_object(dst, src, remove) { key = props[index]; value = src[key]; - if (is_object(value) && dst.hasOwnProperty(key) && is_object(dst[key])) + if (is_array(value) && dst.hasOwnProperty(key) && is_array(dst[key])) + update_array(dst[key], value); + + else if (is_object(value) && dst.hasOwnProperty(key) && is_object(dst[key])) update_object(dst[key], value, remove); else Vue.set(dst, key, value); diff --git a/src/js/control-view.js b/src/js/control-view.js index aaead59..0c48b66 100644 --- a/src/js/control-view.js +++ b/src/js/control-view.js @@ -97,7 +97,9 @@ module.exports = { }, - 'state.selected': function () {this.load()} + 'state.selected': function () {this.load()}, + 'state.files': function () { + console.log('Files changed: ' + JSON.stringify(this.state.files))} }, @@ -199,11 +201,10 @@ module.exports = { load: function () { var file = this.state.selected; - if (this.last_file == file || typeof file == 'undefined' || - typeof file == 'null') return; + if (this.last_file == file) return; this.last_file = file; - if (typeof file != 'undefined') this.$broadcast('gcode-load', file); + this.$broadcast('gcode-load', file); this.$broadcast('gcode-line', this.state.line); this.toolpath_progress = 0; this.load_toolpath(file); @@ -213,7 +214,7 @@ module.exports = { load_toolpath: function (file) { this.toolpath = {}; - if (typeof file == 'undefined' || typeof file == 'null') return; + if (!file) return; api.get('path/' + file).done(function (toolpath) { if (this.last_file != file) return; diff --git a/src/js/gcode-viewer.js b/src/js/gcode-viewer.js index 5f0716c..028de4d 100644 --- a/src/js/gcode-viewer.js +++ b/src/js/gcode-viewer.js @@ -67,7 +67,7 @@ module.exports = { rows: [], scrollElem: $(this.$el).find('.clusterize-scroll')[0], contentElem: $(this.$el).find('.clusterize-content')[0], - no_data_text: 'Loading GCode...', + no_data_text: 'GCode viewer...', callbacks: {clusterChanged: this.highlight} }); }, @@ -81,11 +81,12 @@ module.exports = { methods: { load: function (file) { - if (file == this.file || typeof file == 'undefined' || - typeof file == 'null') return; + if (file == this.file) return; this.clear(); this.file = file; + if (!file) return; + var xhr = new XMLHttpRequest(); xhr.open('GET', '/api/file/' + file + '?' + Math.random(), true); xhr.responseType = 'text'; diff --git a/src/js/path-viewer.js b/src/js/path-viewer.js index 30daea2..2c5bca6 100644 --- a/src/js/path-viewer.js +++ b/src/js/path-viewer.js @@ -122,7 +122,11 @@ module.exports = { methods: { update: function () { - if (!this.toolpath.filename && !this.loading) { + if (!this.state.selected) { + this.dirty = true; + this.scene = new THREE.Scene(); + + } else if (!this.toolpath.filename && !this.loading) { this.loading = true; this.dirty = true; this.draw_loading(); diff --git a/src/pug/templates/control-view.pug b/src/pug/templates/control-view.pug index 3f4b116..9876e0d 100644 --- a/src/pug/templates/control-view.pug +++ b/src/pug/templates/control-view.pug @@ -232,6 +232,11 @@ script#control-view-template(type="text/x-template") input(type="file", @change="upload", :disabled="!is_ready", accept="text/*,.nc,.gcode,.gc,.ngc,.txt,.tap,.cnc") + a.pure-button(:disabled="!state.selected", download, + :href="'/api/file/' + state.selected", + title="Download the selected GCode program.") + .fa.fa-download + button.pure-button(title="Delete current GCode program.", @click="deleteGCode = true", :disabled="!state.selected || !is_ready") @@ -253,9 +258,12 @@ script#control-view-template(type="text/x-template") v-model="state.selected", @change="load", :disabled="!is_ready") option(v-for="file in state.files", :value="file") {{file}} - .progress(v-if="toolpath_progress && toolpath_progress < 1") + .progress(v-if="toolpath_progress && toolpath_progress < 1", + title="Simulating GCode to check for errors, calculate ETA and " + + "generate 3D view. You can run GCode before the simulation " + + "finishes.") div(:style="'width:' + (toolpath_progress || 0) * 100 + '%'") - label Simulating run {{(toolpath_progress || 0) | percent}} + label Simulating {{(toolpath_progress || 0) | percent}} path-viewer(:toolpath="toolpath", :state="state", :config="config") gcode-viewer diff --git a/src/py/bbctrl/FileHandler.py b/src/py/bbctrl/FileHandler.py index 9596b08..52cf476 100644 --- a/src/py/bbctrl/FileHandler.py +++ b/src/py/bbctrl/FileHandler.py @@ -31,6 +31,7 @@ import glob import html import logging from tornado import gen +from tornado.web import HTTPError log = logging.getLogger('FileHandler') @@ -55,30 +56,30 @@ class FileHandler(bbctrl.APIHandler): else: # Delete a single file - safe_remove('upload' + filename) + filename = os.path.basename(filename) + safe_remove('upload/' + filename) self.ctrl.preplanner.delete_plans(filename) self.ctrl.state.remove_file(filename) - def put_ok(self, path): + def put_ok(self, *args): gcode = self.request.files['gcode'][0] - filename = gcode['filename'] + filename = os.path.basename(gcode['filename']) if not os.path.exists('upload'): os.mkdir('upload') - path ='upload/' + filename - - with open(path, 'wb') as f: + with open('upload/' + filename, 'wb') as f: f.write(gcode['body']) self.ctrl.preplanner.invalidate(filename) self.ctrl.state.add_file(filename) - log.info('GCode updated: ' + filename) + log.info('GCode received: ' + filename) @gen.coroutine def get(self, filename): - filename = filename[1:] # Remove / + if not filename: raise HTTPError(400, 'Missing filename') + filename = os.path.basename(filename) with open('upload/' + filename, 'r') as f: self.write(f.read()) diff --git a/src/py/bbctrl/State.py b/src/py/bbctrl/State.py index c3cb560..d00b324 100644 --- a/src/py/bbctrl/State.py +++ b/src/py/bbctrl/State.py @@ -111,24 +111,26 @@ class State(object): def clear_files(self): self.select_file('') self.files = [] - self.set('files', self.files) + self.changes['files'] = self.files def add_file(self, filename): - if filename not in self.files: + if not filename in self.files: self.files.append(filename) self.files.sort() - self.set('files', self.files) + self.changes['files'] = self.files self.select_file(filename) def remove_file(self, filename): - if self.get('selected', '') == filename: self.select_file('') - if filename in self.files: self.files.remove(filename) - self.set('files', self.files) + self.changes['files'] = self.files + + if self.get('selected', filename) == filename: + if len(self.files): self.select_file(self.files[0]) + else: self.select_file('') def select_file(self, filename): self.set('selected', filename) diff --git a/src/py/bbctrl/Web.py b/src/py/bbctrl/Web.py index f29c28f..ee24ea0 100644 --- a/src/py/bbctrl/Web.py +++ b/src/py/bbctrl/Web.py @@ -467,7 +467,7 @@ class Web(tornado.web.Application): (r'/api/config/reset', ConfigResetHandler), (r'/api/firmware/update', FirmwareUpdateHandler), (r'/api/upgrade', UpgradeHandler), - (r'/api/file(/[^/]+)', bbctrl.FileHandler), + (r'/api/file(/[^/]+)?', bbctrl.FileHandler), (r'/api/path/([^/]+)((/positions)|(/speeds))?', PathHandler), (r'/api/home(/[xyzabcXYZABC]((/set)|(/clear))?)?', HomeHandler), (r'/api/start', StartHandler), diff --git a/src/stylus/style.styl b/src/stylus/style.styl index 44f5776..a57d997 100644 --- a/src/stylus/style.styl +++ b/src/stylus/style.styl @@ -189,7 +189,7 @@ span.unit height 12em > select, > input:not([type=checkbox]) - min-width 13em + min-width 11em > tt min-width 15.25em @@ -404,10 +404,10 @@ span.unit clear both > * - margin 0.25em + margin 0.25em 0.125em select - max-width 13em + max-width 11em .progress display inline-block @@ -415,7 +415,7 @@ span.unit line-height 2em border 1px solid #aaa border-radius 3px - width 327px + width 300px vertical-align middle text-align center