From 463b6549f6f3a42845808473d88e48d9ce0fd42d Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Mon, 27 Jun 2016 15:37:52 -0400 Subject: [PATCH 01/25] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a35f8532d..b063776cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,8 +60,10 @@ Released: July 1, 2016 - [ ] core: Investigate if there is a way to manage an oauth dialog and not navigate away from Uppy; Put entire(?) state into oauth redirect urls / LocalStorage with an identifier ? (@hedgerh) - [ ] core: Rethink UI (@arturi) +- [x] core: resize image file previews (to 100x100px) for performance (@arturi) - [ ] server: add tus-js-client when it's node-ready (@hedgerh) - [ ] server: make uppy-server talk to uppy-client in the browser, use websockets. (@hedgerh) +- [ ] dashboard: new “workspace” plugin, main area that allows for drag & drop and shows progress/actions on files, inspired by ProgressDrawer - [x] website: add new logos and blog (@arturi) - [x] drive: Return `cb` after writing all files https://github.com/transloadit/uppy-server/commit/4f1795bc55869fd098a5c81a80edac504fa7324a#commitcomment-17385433 (@hedgerh) - [x] server: Make Google Drive files to actually upload to the endpoint (@hedgerh) From 23e81bb8d78bc6509ae9b99c53d10fb15d9553e2 Mon Sep 17 00:00:00 2001 From: Harry Hedger Date: Tue, 28 Jun 2016 01:49:26 -0400 Subject: [PATCH 02/25] Google Drive client side web sockets --- src/core/UppySocket.js | 26 ++++++++++++++++++++++++++ src/plugins/GoogleDrive.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/core/UppySocket.js diff --git a/src/core/UppySocket.js b/src/core/UppySocket.js new file mode 100644 index 000000000..e5fe1faef --- /dev/null +++ b/src/core/UppySocket.js @@ -0,0 +1,26 @@ +export default class UppySocket { + constructor (opts) { + this.isOpen = false + this.socket = new WebSocket(opts.target) + + this.socket.onopen = (e) => { + this.emit('google:get', { + fileId: '1uPumltHjPmC57_Ljc5onxmtpHziDdId7WDKU9biBV7g', + target: 'api2.transloadit.com' + }) + } + + this.socket.onmessage = (e) => { + console.log(e.data) + } + + this.emit = this.emit.bind(this) + } + + emit (action, payload) { + this.socket.send(JSON.stringify({ + action, + payload + })) + } +} diff --git a/src/plugins/GoogleDrive.js b/src/plugins/GoogleDrive.js index 4b443b7fc..7623e4260 100644 --- a/src/plugins/GoogleDrive.js +++ b/src/plugins/GoogleDrive.js @@ -3,6 +3,8 @@ import Plugin from './Plugin' import 'whatwg-fetch' import yo from 'yo-yo' +import UppySocket from '../core/UppySocket' + export default class Google extends Plugin { constructor (core, opts) { super(core, opts) @@ -33,6 +35,32 @@ export default class Google extends Plugin { // merge default options with the ones set by user this.opts = Object.assign({}, defaultOptions, opts) + const socket = new UppySocket({ + target: 'ws://localhost:9876' + }) + + if (socket.isOpen) { + socket.emit('google:get', { + fileId: '1uPumltHjPmC57_Ljc5onxmtpHziDdId7WDKU9biBV7g', + target: 'api2.transloadit.com' + }) + } + // const socket = new WebSocket('ws://localhost:9876') + + // socket.onopen = (e) => { + // socket.send(JSON.stringify({ + // action: 'google:get', + // payload: { + // fileId: '1uPumltHjPmC57_Ljc5onxmtpHziDdId7WDKU9biBV7g', + // target: 'api2.transloadit.com' + // } + // })) + // console.log(socket) + // } + + // socket.onmessage = (e) => { + // console.log(e.data) + // } } install () { From ef709cbc6b90546b2f14ed89e34c6b91986e6192 Mon Sep 17 00:00:00 2001 From: Kevin van Zonneveld Date: Tue, 28 Jun 2016 17:38:11 +0200 Subject: [PATCH 03/25] Launch the Uppy begins post --- website/src/_posts/2015-10-uppy-begins.md | 41 +++++++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/website/src/_posts/2015-10-uppy-begins.md b/website/src/_posts/2015-10-uppy-begins.md index 75c603325..463d807f5 100644 --- a/website/src/_posts/2015-10-uppy-begins.md +++ b/website/src/_posts/2015-10-uppy-begins.md @@ -1,6 +1,41 @@ --- -title: Uppy Begins -date: 2015-10-26 +title: Uppy: let’s teach an old dog some new tricks +date: 2016-06-28 +author: arturi --- -> On November 26 we gathered in Skype and that’s how Uppy was born. We didn’t know it would be called Uppy yet. +## Uppy: let’s teach an old dog some new tricks + +For the past six months, we have been working hard on uppy.io. We feel that it is high time we gave you a look behind the scenes: what are we working on, and why. + +The way uploading works has not changed in a meaningful way since the days of our trusty old 56 kbit/s modems. Of course, files have gotten bigger and speeds have increased, but that is more or less all there is to say. If it were up to us – and we hope it is – that is all about to change. + +We at [Transloadit](https://transloadit.com/) are on a mission to change the way the world does uploading. To accomplish this, our first step has been to develop an open protocol for resumable file uploads, called [‘tus’](http://tus.io/). Finally, that 2GB video upload from your smartphone doesn’t have to start over when your train passes through a tunnel! The protocol got [Hacker News excited](https://news.ycombinator.com/item?id=10591348) on several occasions and is being deployed by, among others, our friends at Vimeo. Now that a stable version 1.0 of ‘tus’ has been released, it is time to put it to the test. A protocol without real-world applications is nothing more than a meaningless document, after all. + +We are therefore excited to tell you about Uppy: the file uploader that will certainly fetch more than just your newspaper. + +### Why the need for another file uploader? + +It is true, there are indeed already a good few file uploading solutions out there ([Dropzone](http://www.dropzonejs.com/), for instance, is quite good). And – for the most part – they do their job. Nevertheless, they are quite limited in their functionality: + +* You can drag and drop files from local disk, but uploaders that supports Instagram, Dropbox or Google Drive are scarce. The ones out there lock you in with vendors and are hard to customize for own use. + +* File uploaders are seldom mindful of the existence of encoding and processing backends, while the reality is that files often require some form of processing and that the end user would like to receive progress updates with regard to that. + +* None of the currently available file uploaders make use of the standardized resumability that ‘tus’ provides, which makes them less than ideal for handling larger files. + +* Lastly, we feel that the current solutions are sometimes dropping the ball when it comes to a polished user experience. We aim to fix that. + +All in all, we think there is definitely some ‘trouble at the old mill’ here and it’s time to let Uppy take care of that! + +### Our plans for Uppy + +Uppy will be a JavaScript file uploader that allows you to fetch files, not only from your local disk, but also from places like Dropbox, Instagram, Google Drive, webcams and remote URLs. It will have a modular, plugin-based design, making it lightweight and customizable. +Cute on the outside, the core of Uppy is very robust – thanks to resumability through 'tus'. We are confident that Uppy will be able to send even the biggest of files over the smallest of tubes. +Uppy will also offer first class support for accessing Transloadit’s uploading and encoding backend, making it incredibly versatile. Of course, these are all ultimately just plugins, and Uppy can just as easily be used with your own backend – meaning no need to pay any subscription fees. + +We are intent on making the user experience as smooth and satisfying as possible, in terms of both functionality and visual design. Uppy will have a beautiful, themeable UI and it will look – and work – great on mobile platforms as well. While we hope that advanced users will love the customizable nature of Uppy, an ample selection of presets will also be there to make sure that novice users are not going to be lost in the woods. + +Lastly, and this is a point of special significance to us, Uppy will be completely open source. When Uppy is finished, you will be free to use it for whatever you like. Until that time, we very much welcome your ideas and contributions. There are still a lot of decisions to be made and this is the perfect time to come and influence the end product. + +We are going to work hard on bringing you the best file uploader possible and we’ll keep you informed about the development process on [uppy.io](http://uppy.io/). We can’t wait for you to meet Uppy! From e7246fc9d6463b87378ba8ca4c47d4de3f06aae7 Mon Sep 17 00:00:00 2001 From: Harry Hedger Date: Fri, 1 Jul 2016 11:39:00 -0400 Subject: [PATCH 04/25] Client side websockets. File uploading and fetching from Google. --- src/core/Core.js | 10 ++ src/core/UppySocket.js | 56 ++++++++-- src/plugins/GoogleDrive.js | 203 +++++++++++++------------------------ src/plugins/Tus10.js | 35 ++----- 4 files changed, 136 insertions(+), 168 deletions(-) diff --git a/src/core/Core.js b/src/core/Core.js index 0c030455f..5cbd53a37 100644 --- a/src/core/Core.js +++ b/src/core/Core.js @@ -2,6 +2,7 @@ import Utils from '../core/Utils' import Translator from '../core/Translator' import yo from 'yo-yo' import ee from 'events' +import UppySocket from './UppySocket' /** * Main Uppy core @@ -31,6 +32,7 @@ export default class Core { this.translator = new Translator({locales: this.opts.locales}) this.i18n = this.translator.translate.bind(this.translator) + this.initSocket = this.initSocket.bind(this) this.emitter = new ee.EventEmitter() @@ -333,4 +335,12 @@ export default class Core { // .catch((error) => this.log('Upload result -> failed:', error)) // }) } + + initSocket (opts) { + if (!this.socket) { + this.socket = new UppySocket(opts) + } + + return this.socket + } } diff --git a/src/core/UppySocket.js b/src/core/UppySocket.js index e5fe1faef..ae6b1759b 100644 --- a/src/core/UppySocket.js +++ b/src/core/UppySocket.js @@ -1,26 +1,68 @@ +import ee from 'events' + export default class UppySocket { constructor (opts) { + this.queued = [] this.isOpen = false this.socket = new WebSocket(opts.target) + this.emitter = new ee.EventEmitter() this.socket.onopen = (e) => { - this.emit('google:get', { - fileId: '1uPumltHjPmC57_Ljc5onxmtpHziDdId7WDKU9biBV7g', - target: 'api2.transloadit.com' - }) + this.isOpen = true + + while (this.queued.length > 0 && this.isOpen) { + const first = this.queued[0] + this.send(first.action, first.payload) + this.queued = this.queued.slice(1) + } } - this.socket.onmessage = (e) => { - console.log(e.data) + this.socket.onclose = (e) => { + this.isOpen = false } + this._handleMessage = this._handleMessage.bind(this) + + this.socket.onmessage = this._handleMessage + this.emit = this.emit.bind(this) + this.on = this.on.bind(this) + this.once = this.once.bind(this) + this.send = this.send.bind(this) } - emit (action, payload) { + send (action, payload) { + // attach uuid + + if (!this.isOpen) { + this.queued.push({action, payload}) + return + } + this.socket.send(JSON.stringify({ action, payload })) } + + on (action, handler) { + this.emitter.on(action, handler) + } + + emit (action, payload) { + this.emitter.emit(action, payload) + } + + once (action, handler) { + this.emitter.once(action, handler) + } + + _handleMessage (e) { + try { + const message = JSON.parse(e.data) + this.emit(message.action, message.payload) + } catch (err) { + console.log(err) + } + } } diff --git a/src/plugins/GoogleDrive.js b/src/plugins/GoogleDrive.js index 7623e4260..9194cae19 100644 --- a/src/plugins/GoogleDrive.js +++ b/src/plugins/GoogleDrive.js @@ -3,14 +3,12 @@ import Plugin from './Plugin' import 'whatwg-fetch' import yo from 'yo-yo' -import UppySocket from '../core/UppySocket' - export default class Google extends Plugin { constructor (core, opts) { super(core, opts) this.type = 'acquirer' this.id = 'GoogleDrive' - this.titile = 'Google Drive' + this.title = 'Google Drive' this.icon = yo` @@ -18,13 +16,18 @@ export default class Google extends Plugin { ` this.files = [] - this.renderBrowserItem = this.renderBrowserItem.bind(this) - this.filterItems = this.filterItems.bind(this) - this.filterQuery = this.filterQuery.bind(this) + + // Logic this.addFile = this.addFile.bind(this) this.getFolder = this.getFolder.bind(this) this.handleClick = this.handleClick.bind(this) this.logout = this.logout.bind(this) + + // Visual + this.renderBrowserItem = this.renderBrowserItem.bind(this) + this.filterItems = this.filterItems.bind(this) + this.filterQuery = this.filterQuery.bind(this) + this.renderAuth = this.renderAuth.bind(this) this.renderBrowser = this.renderBrowser.bind(this) this.sortByTitle = this.sortByTitle.bind(this) this.sortByDate = this.sortByDate.bind(this) @@ -35,32 +38,38 @@ export default class Google extends Plugin { // merge default options with the ones set by user this.opts = Object.assign({}, defaultOptions, opts) - const socket = new UppySocket({ - target: 'ws://localhost:9876' + + this.socket = this.core.initSocket({ + target: 'ws://localhost:3020/' }) - if (socket.isOpen) { - socket.emit('google:get', { - fileId: '1uPumltHjPmC57_Ljc5onxmtpHziDdId7WDKU9biBV7g', - target: 'api2.transloadit.com' + this.socket.on('google.auth.pass', () => { + this.getFolder(this.core.getState().googleDrive.directory.id) + }) + + this.socket.on('google.list.ok', (data) => { + let folders = [] + let files = [] + data.items.forEach((item) => { + if (item.mimeType === 'application/vnd.google-apps.folder') { + folders.push(item) + } else { + files.push(item) + } }) - } - // const socket = new WebSocket('ws://localhost:9876') - // socket.onopen = (e) => { - // socket.send(JSON.stringify({ - // action: 'google:get', - // payload: { - // fileId: '1uPumltHjPmC57_Ljc5onxmtpHziDdId7WDKU9biBV7g', - // target: 'api2.transloadit.com' - // } - // })) - // console.log(socket) - // } + this.updateState({ + folders, + files, + authenticated: true + }) + }) - // socket.onmessage = (e) => { - // console.log(e.data) - // } + this.socket.on('google.auth.fail', () => { + this.updateState({ + authenticated: false + }) + }) } install () { @@ -84,18 +93,6 @@ export default class Google extends Plugin { this.target = this.mount(target, plugin) this.checkAuthentication() - .then((authenticated) => { - this.updateState({authenticated}) - - if (authenticated) { - return this.getFolder(this.core.getState().googleDrive.directory.id) - } - - return authenticated - }) - .then((newState) => { - this.updateState(newState) - }) return } @@ -125,29 +122,7 @@ export default class Google extends Plugin { * @return {Promise} authentication status */ checkAuthentication () { - return fetch(`${this.opts.host}/google/authorize`, { - method: 'get', - credentials: 'include', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - } - }) - .then((res) => { - if (res.status >= 200 && res.status <= 300) { - return res.json() - } else { - this.updateState({ - authenticated: false, - error: true - }) - let error = new Error(res.statusText) - error.response = res - throw error - } - }) - .then((data) => data.isAuthenticated) - .catch((err) => err) + this.socket.send('google.auth') } /** @@ -155,42 +130,9 @@ export default class Google extends Plugin { * @param {String} id Folder id * @return {Promise} Folders/files in folder */ - getFolder (id = 'root') { - return fetch(`${this.opts.host}/google/list?dir=${id}`, { - method: 'get', - credentials: 'include', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - } - }) - .then((res) => { - if (res.status >= 200 && res.status <= 300) { - return res.json().then((data) => { - // let result = Utils.groupBy(data.items, (item) => item.mimeType) - let folders = [] - let files = [] - data.items.forEach((item) => { - if (item.mimeType === 'application/vnd.google-apps.folder') { - folders.push(item) - } else { - files.push(item) - } - }) - return { - folders, - files - } - }) - } else { - this.handleError(res) - let error = new Error(res.statusText) - error.response = res - throw error - } - }) - .catch((err) => { - return err + getFolder (dir = 'root') { + this.socket.send('google.list', { + dir }) } @@ -226,11 +168,10 @@ export default class Google extends Plugin { data: file, name: file.title, type: this.getFileType(file), - isRemote: true, remote: { - url: `${this.opts.host}/google/get?fileId=${file.id}`, - body: { - fileId: file.id + action: 'google.get', + payload: { + id: file.id } } } @@ -239,41 +180,30 @@ export default class Google extends Plugin { } handleError (response) { - this.checkAuthentication() - .then((authenticated) => { - this.updateState({authenticated}) - }) + // this.checkAuthentication() + // .then((authenticated) => { + // this.updateState({authenticated}) + // }) } /** * Removes session token on client side. */ logout () { - fetch(`${this.opts.host}/google/logout?redirect=${location.href}`, { - method: 'get', - credentials: 'include', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' + this.socket.once('google.logout.ok', () => { + const newState = { + authenticated: false, + files: [], + folders: [], + directory: [{ + title: 'My Drive', + id: 'root' + }] } + console.log('okie') + this.updateState(newState) }) - .then((res) => res.json()) - .then((res) => { - if (res.ok) { - console.log('ok') - const newState = { - authenticated: false, - files: [], - folders: [], - directory: { - title: 'My Drive', - id: 'root' - } - } - - this.updateState(newState) - } - }) + this.socket.send('google.logout') } getFileType (file) { @@ -377,15 +307,20 @@ export default class Google extends Plugin { * Render user authentication view */ renderAuth () { - const state = btoa(JSON.stringify({ - redirect: location.href.split('#')[0] - })) + const link = `${this.opts.host}/connect/google` + + const handleAuth = (e) => { + e.preventDefault() + const authWindow = window.open(link) + this.socket.once('google.auth.complete', () => { + authWindow.close() + }) + } - const link = `${this.opts.host}/connect/google?state=${state}` return yo`

You need to authenticate with Google before selecting files.

- Authenticate + Authenticate
` } diff --git a/src/plugins/Tus10.js b/src/plugins/Tus10.js index e5f855c2c..85abb86fd 100644 --- a/src/plugins/Tus10.js +++ b/src/plugins/Tus10.js @@ -70,7 +70,7 @@ export default class Tus10 extends Plugin { const filesForUpload = {} Object.keys(files).forEach((file) => { - if (files[file].progress === 0 || files[file].isRemote) { + if (files[file].progress === 0 || files[file].remote) { filesForUpload[file] = files[file] } }) @@ -86,10 +86,10 @@ export default class Tus10 extends Plugin { const current = parseInt(i, 10) + 1 const total = files.length - if (!files[i].isRemote) { - uploaders.push(this.upload(file, current, total)) - } else { + if (files[i].remote) { uploaders.push(this.uploadRemote(file, current, total)) + } else { + uploaders.push(this.upload(file, current, total)) } } @@ -102,30 +102,11 @@ export default class Tus10 extends Plugin { uploadRemote (file, current, total) { return new Promise((resolve, reject) => { - fetch(file.remote.url, { - method: 'post', - credentials: 'include', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify(Object.assign({}, file.remote.body, { - target: this.opts.endpoint - })) - }) - .then((res) => { - if (res.status >= 200 && res.status <= 300) { - this.core.log(`Remote upload of '${file.name}' successful`) - return resolve('Success') - } - this.core.log(`Remote upload of file '${file.name}' failed`) - - if (file.acquiredBy.handleError) { - file.acquiredBy.handleError(res) - } - - return reject(new Error('Error: ' + res.statusText)) + const payload = Object.assign({}, file.remote.payload, { + target: this.opts.endpoint, + protocol: 'tus' }) + this.core.socket.send(file.remote.action, payload) }) } From 5d15a100ba973abe4096f053ea50033ae785bc99 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Fri, 1 Jul 2016 14:24:22 -0400 Subject: [PATCH 05/25] Update CHANGELOG.md --- CHANGELOG.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b063776cb..64e4e77dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,6 @@ first Friday of every new month. Ideas that will be planned and find their way into a release at one point - [ ] build: go over `package.json` together and clean up npm run scripts (@arturi, @hedgerh, @kvz) -- [ ] build: browsersync does 3 refreshes, can that be one? should be doable via cooldown/debounce? - [ ] build: investigate Rollup someday, for tree-shaking and smaller dist https://github.com/substack/node-browserify/issues/1379#issuecomment-183383199, https://github.com/nolanlawson/rollupify - [ ] core: Decouple rendering from Plugins and try to make Uppy work with React (add basic example) to remain aware of possible issues (@hedgerh), look at https://github.com/akiran/react-slick - [ ] core: Have base styles, be explicit about fonts, etc @@ -59,14 +58,16 @@ Theme: Remote Uploads, UI Redesign Released: July 1, 2016 - [ ] core: Investigate if there is a way to manage an oauth dialog and not navigate away from Uppy; Put entire(?) state into oauth redirect urls / LocalStorage with an identifier ? (@hedgerh) -- [ ] core: Rethink UI (@arturi) +- [ ] core: Rethink UI: Part I (@arturi) +- [x] core: let user cancel uploads in progress (@arturi) - [x] core: resize image file previews (to 100x100px) for performance (@arturi) - [ ] server: add tus-js-client when it's node-ready (@hedgerh) - [ ] server: make uppy-server talk to uppy-client in the browser, use websockets. (@hedgerh) -- [ ] dashboard: new “workspace” plugin, main area that allows for drag & drop and shows progress/actions on files, inspired by ProgressDrawer +- [x] dashboard: new “workspace” plugin, main area that allows for drag & drop and shows progress/actions on files, inspired by ProgressDrawer - [x] website: add new logos and blog (@arturi) - [x] drive: Return `cb` after writing all files https://github.com/transloadit/uppy-server/commit/4f1795bc55869fd098a5c81a80edac504fa7324a#commitcomment-17385433 (@hedgerh) - [x] server: Make Google Drive files to actually upload to the endpoint (@hedgerh) +- [x] build: browsersync does 3 refreshes, can that be one? should be doable via cooldown/debounce? -> get rid of require shortcuts (@arturi) - [x] build: regular + min + gzipped versions of the bundle (@arturi) - [x] workspace: interface research for better file selection / progress representation (@arturi) From bbbc248c9750b98670983ec1e88af8176f2305cc Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Fri, 1 Jul 2016 16:07:18 -0400 Subject: [PATCH 06/25] Fix title --- .../{2015-10-uppy-begins.md => 2016-06-uppy-begins.md} | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) rename website/src/_posts/{2015-10-uppy-begins.md => 2016-06-uppy-begins.md} (95%) diff --git a/website/src/_posts/2015-10-uppy-begins.md b/website/src/_posts/2016-06-uppy-begins.md similarity index 95% rename from website/src/_posts/2015-10-uppy-begins.md rename to website/src/_posts/2016-06-uppy-begins.md index 463d807f5..bacdd9390 100644 --- a/website/src/_posts/2015-10-uppy-begins.md +++ b/website/src/_posts/2016-06-uppy-begins.md @@ -1,18 +1,16 @@ --- -title: Uppy: let’s teach an old dog some new tricks +title: "Uppy: let’s teach an old dog some new tricks" date: 2016-06-28 author: arturi --- -## Uppy: let’s teach an old dog some new tricks - For the past six months, we have been working hard on uppy.io. We feel that it is high time we gave you a look behind the scenes: what are we working on, and why. The way uploading works has not changed in a meaningful way since the days of our trusty old 56 kbit/s modems. Of course, files have gotten bigger and speeds have increased, but that is more or less all there is to say. If it were up to us – and we hope it is – that is all about to change. We at [Transloadit](https://transloadit.com/) are on a mission to change the way the world does uploading. To accomplish this, our first step has been to develop an open protocol for resumable file uploads, called [‘tus’](http://tus.io/). Finally, that 2GB video upload from your smartphone doesn’t have to start over when your train passes through a tunnel! The protocol got [Hacker News excited](https://news.ycombinator.com/item?id=10591348) on several occasions and is being deployed by, among others, our friends at Vimeo. Now that a stable version 1.0 of ‘tus’ has been released, it is time to put it to the test. A protocol without real-world applications is nothing more than a meaningless document, after all. -We are therefore excited to tell you about Uppy: the file uploader that will certainly fetch more than just your newspaper. +We are therefore excited to tell you about Uppy: the file uploader that will certainly fetch more than just your newspaper. ### Why the need for another file uploader? @@ -31,11 +29,11 @@ All in all, we think there is definitely some ‘trouble at the old mill’ here ### Our plans for Uppy Uppy will be a JavaScript file uploader that allows you to fetch files, not only from your local disk, but also from places like Dropbox, Instagram, Google Drive, webcams and remote URLs. It will have a modular, plugin-based design, making it lightweight and customizable. -Cute on the outside, the core of Uppy is very robust – thanks to resumability through 'tus'. We are confident that Uppy will be able to send even the biggest of files over the smallest of tubes. +Cute on the outside, the core of Uppy is very robust – thanks to resumability through 'tus'. We are confident that Uppy will be able to send even the biggest of files over the smallest of tubes. Uppy will also offer first class support for accessing Transloadit’s uploading and encoding backend, making it incredibly versatile. Of course, these are all ultimately just plugins, and Uppy can just as easily be used with your own backend – meaning no need to pay any subscription fees. We are intent on making the user experience as smooth and satisfying as possible, in terms of both functionality and visual design. Uppy will have a beautiful, themeable UI and it will look – and work – great on mobile platforms as well. While we hope that advanced users will love the customizable nature of Uppy, an ample selection of presets will also be there to make sure that novice users are not going to be lost in the woods. -Lastly, and this is a point of special significance to us, Uppy will be completely open source. When Uppy is finished, you will be free to use it for whatever you like. Until that time, we very much welcome your ideas and contributions. There are still a lot of decisions to be made and this is the perfect time to come and influence the end product. +Lastly, and this is a point of special significance to us, Uppy will be completely open source. When Uppy is finished, you will be free to use it for whatever you like. Until that time, we very much welcome your ideas and contributions. There are still a lot of decisions to be made and this is the perfect time to come and influence the end product. We are going to work hard on bringing you the best file uploader possible and we’ll keep you informed about the development process on [uppy.io](http://uppy.io/). We can’t wait for you to meet Uppy! From 23cf2e7778faabb92340ddb829e5007ba056ae8e Mon Sep 17 00:00:00 2001 From: Harry Hedger Date: Fri, 1 Jul 2016 17:03:14 -0400 Subject: [PATCH 07/25] Removed hardcoded websocket url --- src/plugins/GoogleDrive.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/GoogleDrive.js b/src/plugins/GoogleDrive.js index 9194cae19..223cef67f 100644 --- a/src/plugins/GoogleDrive.js +++ b/src/plugins/GoogleDrive.js @@ -39,8 +39,10 @@ export default class Google extends Plugin { // merge default options with the ones set by user this.opts = Object.assign({}, defaultOptions, opts) + const host = this.opts.host.replace(/^https?:\/\//, '') + this.socket = this.core.initSocket({ - target: 'ws://localhost:3020/' + target: 'ws://' + host }) this.socket.on('google.auth.pass', () => { From 3a2b7a167d8fdb898d012263d1405b49d6233980 Mon Sep 17 00:00:00 2001 From: Harry Hedger Date: Fri, 1 Jul 2016 17:09:32 -0400 Subject: [PATCH 08/25] Update CHANGELOG.md --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64e4e77dc..e28f336c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,12 +57,12 @@ Theme: Remote Uploads, UI Redesign Released: July 1, 2016 -- [ ] core: Investigate if there is a way to manage an oauth dialog and not navigate away from Uppy; Put entire(?) state into oauth redirect urls / LocalStorage with an identifier ? (@hedgerh) +- [x] core: Investigate if there is a way to manage an oauth dialog and not navigate away from Uppy; Put entire(?) state into oauth redirect urls / LocalStorage with an identifier ? (@hedgerh) - [ ] core: Rethink UI: Part I (@arturi) - [x] core: let user cancel uploads in progress (@arturi) - [x] core: resize image file previews (to 100x100px) for performance (@arturi) -- [ ] server: add tus-js-client when it's node-ready (@hedgerh) -- [ ] server: make uppy-server talk to uppy-client in the browser, use websockets. (@hedgerh) +- [x] server: add tus-js-client when it's node-ready (@hedgerh) +- [x] server: make uppy-server talk to uppy-client in the browser, use websockets. (@hedgerh) - [x] dashboard: new “workspace” plugin, main area that allows for drag & drop and shows progress/actions on files, inspired by ProgressDrawer - [x] website: add new logos and blog (@arturi) - [x] drive: Return `cb` after writing all files https://github.com/transloadit/uppy-server/commit/4f1795bc55869fd098a5c81a80edac504fa7324a#commitcomment-17385433 (@hedgerh) From 8bc7a72df1be094e7ff025938d8868c09f71f19c Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Fri, 1 Jul 2016 17:40:51 -0400 Subject: [PATCH 09/25] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e28f336c3..f1843e67c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ Ideas that will be planned and find their way into a release at one point - [ ] website: Make a gif/video of Uppy Modal or DragDrop demo (drag & drop a few files -> upload happens) - [ ] website: scrollbars on code samples (can’t reproduce!) (@arturi) - [ ] core: accessibility research +- [ ] test: add next-update https://www.npmjs.com/package/next-update to check if packages we use can be safely updated ## 0.8.0 From 5067252cb84efa2b017a782efdc2afb65a082b1d Mon Sep 17 00:00:00 2001 From: Harry Hedger Date: Fri, 1 Jul 2016 18:11:29 -0400 Subject: [PATCH 10/25] Debugging in GD --- src/plugins/GoogleDrive.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/plugins/GoogleDrive.js b/src/plugins/GoogleDrive.js index 223cef67f..ced665a6b 100644 --- a/src/plugins/GoogleDrive.js +++ b/src/plugins/GoogleDrive.js @@ -42,14 +42,21 @@ export default class Google extends Plugin { const host = this.opts.host.replace(/^https?:\/\//, '') this.socket = this.core.initSocket({ - target: 'ws://' + host + target: 'ws://' + host + '/' }) this.socket.on('google.auth.pass', () => { + console.log('google.auth.pass') this.getFolder(this.core.getState().googleDrive.directory.id) }) + this.socket.on('uppy.debug', (payload) => { + console.log('GOOGLE DEBUG:') + console.log(payload) + }) + this.socket.on('google.list.ok', (data) => { + console.log('google.list.ok') let folders = [] let files = [] data.items.forEach((item) => { @@ -68,6 +75,7 @@ export default class Google extends Plugin { }) this.socket.on('google.auth.fail', () => { + console.log('google.auth.fail') this.updateState({ authenticated: false }) @@ -315,6 +323,7 @@ export default class Google extends Plugin { e.preventDefault() const authWindow = window.open(link) this.socket.once('google.auth.complete', () => { + console.log('google.auth.complete') authWindow.close() }) } @@ -322,7 +331,7 @@ export default class Google extends Plugin { return yo`

You need to authenticate with Google before selecting files.

- Authenticate + Authenticate
` } From 0b92fc178515ecc958f95f661112d8b81ea7a8b5 Mon Sep 17 00:00:00 2001 From: Harry Hedger Date: Fri, 1 Jul 2016 18:27:32 -0400 Subject: [PATCH 11/25] Bump for rebuild --- src/plugins/GoogleDrive.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/GoogleDrive.js b/src/plugins/GoogleDrive.js index ced665a6b..d436126b3 100644 --- a/src/plugins/GoogleDrive.js +++ b/src/plugins/GoogleDrive.js @@ -314,7 +314,7 @@ export default class Google extends Plugin { } /** - * Render user authentication view + * Render user authentication view */ renderAuth () { const link = `${this.opts.host}/connect/google` From 3dd50112a46362328b881f3763e9e69465c945b5 Mon Sep 17 00:00:00 2001 From: Harry Hedger Date: Fri, 1 Jul 2016 18:51:05 -0400 Subject: [PATCH 12/25] Client debug --- src/plugins/GoogleDrive.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/plugins/GoogleDrive.js b/src/plugins/GoogleDrive.js index d436126b3..c50f9e318 100644 --- a/src/plugins/GoogleDrive.js +++ b/src/plugins/GoogleDrive.js @@ -74,6 +74,11 @@ export default class Google extends Plugin { }) }) + this.socket.on('google.list.fail', (data) => { + console.log('google.list.fail') + console.log(data) + }) + this.socket.on('google.auth.fail', () => { console.log('google.auth.fail') this.updateState({ From e54d0cf27ec7831253118e0f66c7e662ccc7f8bc Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Fri, 1 Jul 2016 18:53:58 -0400 Subject: [PATCH 13/25] Bare example watch script --- example/index.html | 3 ++- package.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/example/index.html b/example/index.html index 3875e6d3a..17cf5204e 100644 --- a/example/index.html +++ b/example/index.html @@ -9,10 +9,11 @@ - + diff --git a/package.json b/package.json index 4c18e86de..ff187ad7a 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "watch:css": "nodemon --watch src --ext scss -x 'npm run build:css && node website/update.js'", "watch:fast": "npm-run-all --parallel watch:css web:preview", "watch:js": "nodemon --watch src --ext js -x 'npm run build:bundle && node website/update.js'", - "watch": "npm-run-all --parallel watch:js watch:css && node website/update.js", + "watch": "npm-run-all --parallel watch:js watch:css", "web:build": "cd website && node update.js && ./node_modules/.bin/hexo generate --silent && node build-examples.js", "web:clean": "cd website && ./node_modules/.bin/hexo clean", "web:deploy": "npm-run-all web:install web:disc docs web:build && ./bin/web-deploy", From b9b9feff1aecd70cdec0457a20942869da899e52 Mon Sep 17 00:00:00 2001 From: Harry Hedger Date: Fri, 1 Jul 2016 19:15:27 -0400 Subject: [PATCH 14/25] debug --- src/plugins/GoogleDrive.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/plugins/GoogleDrive.js b/src/plugins/GoogleDrive.js index c50f9e318..5b53148de 100644 --- a/src/plugins/GoogleDrive.js +++ b/src/plugins/GoogleDrive.js @@ -53,6 +53,13 @@ export default class Google extends Plugin { this.socket.on('uppy.debug', (payload) => { console.log('GOOGLE DEBUG:') console.log(payload) + + try { + const pay = JSON.parse(payload) + console.log(pay) + } catch (e) { + console.log(e) + } }) this.socket.on('google.list.ok', (data) => { From 044aa2d5335c98637c120d397f2a288412eda4c2 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Fri, 1 Jul 2016 22:50:40 -0400 Subject: [PATCH 15/25] =?UTF-8?q?Greatly=20improved=20example=20page=20and?= =?UTF-8?q?=20command=20for=20dev=20=E2=80=94=20`watch:example`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 ++++- example/index.html | 15 +++++++-------- example/main.js | 8 ++++++++ package.json | 14 +++++++++----- 4 files changed, 28 insertions(+), 14 deletions(-) create mode 100644 example/main.js diff --git a/.gitignore b/.gitignore index 4115c7fca..81af1c5f6 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,10 @@ website/public/ website/.deploy*/ website/src/_drafts website/themes/uppy/source/uppy/ -npm-debug.log* website/themes/uppy/_config.yml + +npm-debug.log* config/ nohup.out + +example/bundle.js diff --git a/example/index.html b/example/index.html index 17cf5204e..e66e09f06 100644 --- a/example/index.html +++ b/example/index.html @@ -7,15 +7,14 @@

Uppy is here

- - - + + diff --git a/example/main.js b/example/main.js index 058421cda..e8d2b4f1d 100644 --- a/example/main.js +++ b/example/main.js @@ -2,7 +2,10 @@ const Uppy = require('../src/index.js') const uppy = new Uppy.Core({debug: true}) .use(Uppy.plugins.Modal, {trigger: '#uppyModalOpener'}) - .use(Uppy.plugins.Dashboard, {target: Uppy.plugins.Modal}) + .use(Uppy.plugins.DragDrop, {target: Uppy.plugins.Modal}) + // .use(Uppy.plugins.Dashboard, {target: Uppy.plugins.Modal}) .use(Uppy.plugins.Dummy, {target: Uppy.plugins.Modal}) uppy.run() + +document.querySelector('#uppyModalOpener').click() From 50253dcc5a4050ff784fa8f6cff934b3b1f12a62 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Fri, 1 Jul 2016 23:29:03 -0400 Subject: [PATCH 17/25] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1843e67c..204864a8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,7 +59,7 @@ Theme: Remote Uploads, UI Redesign Released: July 1, 2016 - [x] core: Investigate if there is a way to manage an oauth dialog and not navigate away from Uppy; Put entire(?) state into oauth redirect urls / LocalStorage with an identifier ? (@hedgerh) -- [ ] core: Rethink UI: Part I (@arturi) +- [x] core: Rethink UI: Part I (interface research for better file selection / progress representation) (@arturi) - [x] core: let user cancel uploads in progress (@arturi) - [x] core: resize image file previews (to 100x100px) for performance (@arturi) - [x] server: add tus-js-client when it's node-ready (@hedgerh) @@ -70,7 +70,7 @@ Released: July 1, 2016 - [x] server: Make Google Drive files to actually upload to the endpoint (@hedgerh) - [x] build: browsersync does 3 refreshes, can that be one? should be doable via cooldown/debounce? -> get rid of require shortcuts (@arturi) - [x] build: regular + min + gzipped versions of the bundle (@arturi) -- [x] workspace: interface research for better file selection / progress representation (@arturi) +- [x] build: set up a simple and quick dev workflow — watch:example (@arturi) ## 0.6.4 From f2ca8f91b24c5c434c0919ead8f4dae61965b610 Mon Sep 17 00:00:00 2001 From: Harry Hedger Date: Sat, 2 Jul 2016 20:10:07 -0400 Subject: [PATCH 18/25] Rolled back to using http for logout and added success emit for upload success. --- src/plugins/GoogleDrive.js | 43 +++++++++++++++++++++----------------- src/plugins/Tus10.js | 11 ++++++++++ 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/plugins/GoogleDrive.js b/src/plugins/GoogleDrive.js index 5b53148de..b80856e8a 100644 --- a/src/plugins/GoogleDrive.js +++ b/src/plugins/GoogleDrive.js @@ -53,13 +53,6 @@ export default class Google extends Plugin { this.socket.on('uppy.debug', (payload) => { console.log('GOOGLE DEBUG:') console.log(payload) - - try { - const pay = JSON.parse(payload) - console.log(pay) - } catch (e) { - console.log(e) - } }) this.socket.on('google.list.ok', (data) => { @@ -212,22 +205,34 @@ export default class Google extends Plugin { * Removes session token on client side. */ logout () { - this.socket.once('google.logout.ok', () => { - const newState = { - authenticated: false, - files: [], - folders: [], - directory: [{ - title: 'My Drive', - id: 'root' - }] + fetch(`${this.opts.host}/google/logout?redirect=${location.href}`, { + method: 'get', + credentials: 'include', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' } - console.log('okie') - this.updateState(newState) }) - this.socket.send('google.logout') + .then((res) => res.json()) + .then((res) => { + if (res.ok) { + console.log('ok') + const newState = { + authenticated: false, + files: [], + folders: [], + directory: [{ + title: 'My Drive', + id: 'root' + }] + } + + this.updateState(newState) + } + }) } + getFileType (file) { const fileTypes = { 'application/vnd.google-apps.folder': 'Folder', diff --git a/src/plugins/Tus10.js b/src/plugins/Tus10.js index 85abb86fd..2f249f356 100644 --- a/src/plugins/Tus10.js +++ b/src/plugins/Tus10.js @@ -107,6 +107,17 @@ export default class Tus10 extends Plugin { protocol: 'tus' }) this.core.socket.send(file.remote.action, payload) + this.core.socket.once('upload-success', () => { + console.log('success') + this.core.emitter.emit('upload-success', file) + + this.core.emitter.emit('upload-progress', { + id: file.id, + percentage: 100 + }) + + resolve() + }) }) } From 033bb43801e30738d7624617e86a77168c88f1eb Mon Sep 17 00:00:00 2001 From: Harry Hedger Date: Sat, 2 Jul 2016 20:15:47 -0400 Subject: [PATCH 19/25] Fixed lint issue --- src/plugins/GoogleDrive.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/GoogleDrive.js b/src/plugins/GoogleDrive.js index b80856e8a..52ff32512 100644 --- a/src/plugins/GoogleDrive.js +++ b/src/plugins/GoogleDrive.js @@ -232,7 +232,6 @@ export default class Google extends Plugin { }) } - getFileType (file) { const fileTypes = { 'application/vnd.google-apps.folder': 'Folder', From bec5c51270d197af23ea9df41f09a19b503d55cd Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Tue, 5 Jul 2016 21:29:31 -0400 Subject: [PATCH 20/25] Website blog posts updated --- website/src/_posts/2016-06-0.6.0.md | 43 +++++++++++++++++++++-- website/src/_posts/2016-06-uppy-begins.md | 2 ++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/website/src/_posts/2016-06-0.6.0.md b/website/src/_posts/2016-06-0.6.0.md index 3672380a4..7c74cd444 100644 --- a/website/src/_posts/2016-06-0.6.0.md +++ b/website/src/_posts/2016-06-0.6.0.md @@ -1,8 +1,45 @@ --- -title: Uppy 0.6.0 Released -date: 2016-06-04 +title: We released Uppy 0.6.0 +date: 2016-06-30 +author: aj --- -> Hi! We released Uppy 0.6.0. It was mainly a refactor release, but nonetheless very important, so we are proud. +> Hi! We released Uppy 0.6.0. It was mainly a refactor release, but nonetheless important, so we are proud. + +we worked hard yadda yadda :+1:. We'd like to go over the most important changes: + +## File Previews and Remote File Handling + +* Uppy now shows preview images for, well, images, and a file icon for other types of files +* “Remote files” can now be selected in Uppy. Meaning, you can double click on a file from Google Drive and it will be shown by Uppy in a preview area and everything. Wicked :ghost: + +## Accessibility and Acceptance Tests Stats + +* More accessibility work: when you switch tabs in Modal, it focuses on the first input in that tab +* On our website you can now [see stats]((http://uppy.io/stats)) on how acceptance tests are doing in each browser. If tests pass that generally means that Uppy can succesfully load and upload a file in that particular browser. Pretty neat! + +And here's the full list of things that changed in this relase + +- build: minification of the bundle (@arturi) +- build: revisit sourcemaps for production. can we have them without a mandatory extra request? +- build: supply Uppy es5 and es6 entry points in npm package (@arturi) +- build: switch to https://www.npmjs.com/package/npm-run-all instead of parallelshell (@arturi) +- drive: Make sure uppy-server does not explode on special file types: https://dl.dropboxusercontent.com/s/d4dbxitjt8clo50/2016-05-06%20at%2022.41.png (@hedgerh) +- modal: accessibility. focus on the first input field / button in tab panel (@arturi) +- progressdrawer: figure out crazy rerendering of previews by yoyo/bel: https://github.com/shama/bel/issues/26, https://github.com/shama/bel/issues/27 (@arturi) +- core: substantial refactor of mount & rendering (@arturi) +- core: better state change logs for better debugging (@arturi) +- progressdrawer: improve styles, add preview icons for all (@arturi) +- server: Start implementing the `SERVER-PLAN.md`, remote files should be added to `state.files` and marked as `remote` (@hedgerh) +- test: Add pass/fail Saucelabs flag to acceptance tests (@arturi) +- website: Polish Saucelabs stats (social badge + stats layout) (@arturi) +- meta: Create Uppy logos (@markstory) +- website: fix examples and cleanup (@arturi) +- website: Add Saucelabs badges to uppy.io (@kvz) +- website: fix disappearing icons issue, `postcss-inline-svg` (@arturi) + +We hop you enjoy this release and + +The Uppy Team diff --git a/website/src/_posts/2016-06-uppy-begins.md b/website/src/_posts/2016-06-uppy-begins.md index bacdd9390..6da3bfbf2 100644 --- a/website/src/_posts/2016-06-uppy-begins.md +++ b/website/src/_posts/2016-06-uppy-begins.md @@ -12,6 +12,8 @@ We at [Transloadit](https://transloadit.com/) are on a mission to change the way We are therefore excited to tell you about Uppy: the file uploader that will certainly fetch more than just your newspaper. + + ### Why the need for another file uploader? It is true, there are indeed already a good few file uploading solutions out there ([Dropzone](http://www.dropzonejs.com/), for instance, is quite good). And – for the most part – they do their job. Nevertheless, they are quite limited in their functionality: From 486e496adb637364754a782b052ff24ba15f47d4 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Tue, 5 Jul 2016 21:29:56 -0400 Subject: [PATCH 21/25] Blog layout and menu fix --- website/themes/uppy/layout/partials/main_menu.ejs | 1 + website/themes/uppy/layout/post.ejs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/website/themes/uppy/layout/partials/main_menu.ejs b/website/themes/uppy/layout/partials/main_menu.ejs index 2fa02dcc4..96f94c9ca 100644 --- a/website/themes/uppy/layout/partials/main_menu.ejs +++ b/website/themes/uppy/layout/partials/main_menu.ejs @@ -8,4 +8,5 @@
  • API
  • Examples
  • Stats
  • +
  • Github
  • diff --git a/website/themes/uppy/layout/post.ejs b/website/themes/uppy/layout/post.ejs index e928b1ef9..c102fd8e8 100644 --- a/website/themes/uppy/layout/post.ejs +++ b/website/themes/uppy/layout/post.ejs @@ -1,4 +1,4 @@ -