Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Import from url #588

Merged
merged 11 commits into from
Feb 9, 2018
7,834 changes: 3,807 additions & 4,027 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@
"redux": "^3.7.2",
"replace-x": "^1.5.0",
"sass": "0.5.0",
"tape": "^4.8.0",
"temp-write": "^3.4.0",
"tinyify": "^2.4.0",
"uppy-server": "^0.10.0",
Expand Down
36 changes: 36 additions & 0 deletions src/plugins/Url/UrlUI.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const { h, Component } = require('preact')

class UrlUI extends Component {
constructor (props) {
super(props)
this.handleClick = this.handleClick.bind(this)
}

componentDidMount () {
this.input.focus()
}

handleClick () {
this.props.addFile(this.input.value)
}

render () {
return <div class="uppy-Url">
<input
class="uppy-Url-input"
type="text"
placeholder={this.props.i18n('enterUrlToImport')}
ref={(input) => { this.input = input }}
value="" />
<button
class="uppy-Url-importButton"
type="button"
aria-label={this.props.i18n('addUrl')}
onclick={this.handleClick}>
{this.props.i18n('import')}
</button>
</div>
}
}

module.exports = UrlUI
129 changes: 129 additions & 0 deletions src/plugins/Url/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
const Plugin = require('../../core/Plugin')
const Translator = require('../../core/Translator')
const { h } = require('preact')
const Provider = require('../Provider')
const UrlUI = require('./UrlUI.js')
// const Utils = require('../../core/Utils')
require('whatwg-fetch')

/**
* Link
*
*/
module.exports = class Link extends Plugin {
constructor (uppy, opts) {
super(uppy, opts)
this.id = this.opts.id || 'Url'
this.title = 'Url'
this.type = 'acquirer'
this.icon = () => <svg aria-hidden="true" class="UppyIcon UppyModalTab-icon" width="64" height="64" viewBox="0 0 64 64">
<circle cx="32" cy="32" r="31" />
<g fill-rule="nonzero" fill="#FFF">
<path d="M25.774 47.357a4.077 4.077 0 0 1-5.76 0L16.9 44.24a4.076 4.076 0 0 1 0-5.758l5.12-5.12-1.817-1.818-5.12 5.122a6.651 6.651 0 0 0 0 9.392l3.113 3.116a6.626 6.626 0 0 0 4.699 1.943c1.7 0 3.401-.649 4.697-1.943l10.241-10.243a6.591 6.591 0 0 0 1.947-4.696 6.599 6.599 0 0 0-1.947-4.696l-3.116-3.114-1.817 1.817 3.116 3.114a4.045 4.045 0 0 1 1.194 2.88 4.045 4.045 0 0 1-1.194 2.878L25.774 47.357z" />
<path d="M46.216 14.926a6.597 6.597 0 0 0-4.696-1.946h-.001a6.599 6.599 0 0 0-4.696 1.945L26.582 25.167a6.595 6.595 0 0 0-1.947 4.697 6.599 6.599 0 0 0 1.946 4.698l3.114 3.114 1.818-1.816-3.114-3.114a4.05 4.05 0 0 1-1.194-2.882c0-1.086.424-2.108 1.194-2.878L38.64 16.744a4.042 4.042 0 0 1 2.88-1.194c1.089 0 2.11.425 2.88 1.194l3.114 3.114a4.076 4.076 0 0 1 0 5.758l-5.12 5.12 1.818 1.817 5.12-5.122a6.649 6.649 0 0 0 0-9.393l-3.113-3.114-.003.002z" />
</g>
</svg>

// Set default options and locale
const defaultLocale = {
strings: {
addUrl: 'Add url',
import: 'Import',
enterUrlToImport: 'Enter file url to import'
}
}

const defaultOptions = {
locale: defaultLocale
}

this.opts = Object.assign({}, defaultOptions, opts)

this.locale = Object.assign({}, defaultLocale, this.opts.locale)
this.locale.strings = Object.assign({}, defaultLocale.strings, this.opts.locale.strings)

this.translator = new Translator({locale: this.locale})
this.i18n = this.translator.translate.bind(this.translator)

this.hostname = this.opts.host

// Bind all event handlers for referencability
this.getMeta = this.getMeta.bind(this)
this.addFile = this.addFile.bind(this)

this[this.id] = new Provider(uppy, {
host: this.opts.host,
provider: 'url',
authProvider: 'url'
})
}

getMeta (url) {
return fetch(`${this.hostname}/url/meta`, {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

based on my suggestion 2. and 3. above, we can have this fetch done in ApiCalls

method: 'post',
credentials: 'include',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: url
})
})
.then(this[this.id].onReceiveResponse)
.then((res) => res.json())
}

getFileNameFromUrl (url) {
return url.substring(url.lastIndexOf('/') + 1)
}

addFile (url) {
this.getMeta(url).then((meta) => {
const tagFile = {
source: this.id,
name: this.getFileNameFromUrl(url),
type: meta.type,
data: {
size: meta.size
},
isRemote: true,
body: {
url: url
},
remote: {
host: this.opts.host,
url: `${this.hostname}/url/get`,
body: {
fileId: url,
url: url
}
}
}

this.uppy.log('[Url] Adding remote file')
this.uppy.addFile(tagFile)
.then(() => {
const dashboard = this.uppy.getPlugin('Dashboard')
if (dashboard) dashboard.hideAllPanels()
})
})
}

render (state) {
return <UrlUI
i18n={this.i18n}
addFile={this.addFile} />
}

install () {
const target = this.opts.target
if (target) {
this.mount(target, this)
}
}

uninstall () {
this.unmount()
}
}
2 changes: 1 addition & 1 deletion src/scss/_dashboard.scss
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@
vertical-align: middle;
width: 7px;
height: 7px;
opacity: 0.7;
color: rgba($color-gray, 0.6);

.uppy-Dashboard--wide & {
width: 10px;
Expand Down
31 changes: 31 additions & 0 deletions src/scss/_url.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.uppy-Url {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}

.uppy-Url-input {
width: 80%;
height: 50px;
padding-left: 10px;
font-size: 15px;
border: 1px solid rgba($color-gray, 0.5);
border-right: 0;
}

.uppy-Url-importButton {
@include reset-button();
width: 100px;
height: 50px;
color: $color-white;
background-color: $color-cornflower-blue;
cursor: pointer;
padding: 12px;
}

// .uppy-Url-importButton-icon {
// width: 100%;
// height: 100%;
// }
1 change: 1 addition & 0 deletions src/scss/uppy.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
@import '_dashboard.scss';
@import '_dragdrop.scss';
@import '_provider.scss';
@import '_url.scss';
@import '_progressbar.scss';
@import '_statusbar.scss';
@import '_webcam.scss';
16 changes: 8 additions & 8 deletions website/src/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ alias: api/
order: 0
---

Uppy is a sleek, modular file uploader that integrates seamlessly with any framework. It fetches files from local disk, Google Drive, Dropbox, Instagram, remote URLs, cameras and other exciting locations, and then uploads them to the final destination. It’s fast, easy to use and lets you worry about more important problems than building a file uploader.
Uppy is a sleek, modular file uploader that integrates seamlessly with any framework. It fetches files from local disk, Google Drive, Dropbox, Instagram, remote urls, cameras and other exciting locations, and then uploads them to the final destination. It’s fast, easy to use and lets you worry about more important problems than building a file uploader.

Uppy consists of a core module and [various plugins](/docs/plugins/) for selecting, manipulating and uploading files. Here’s how it works:

Expand All @@ -19,19 +19,19 @@ const uppy = Uppy({ autoProceed: false })
.use(Dashboard, {
trigger: '#select-files'
})
.use(Tus, {endpoint: '//master.tus.io/files/'})
.use(Tus, {endpoint: 'https://master.tus.io/files/'})
.run()

uppy.on('complete', (result) => {
console.log(`Upload complete! We’ve uploaded these files: ${result.successful}`)
})
```

[Try it live](/examples/dashboard/)
[Try it live!](/examples/dashboard/)

Drag and Drop, Webcam, basic file manipulation (adding metadata), uploading via tus resumable uploads or XHR/Multipart is all possible using just the uppy client module.

Adding [Uppy Server](/docs/server/) to the mix enables remote sources such as Instagram, Google Drive and Dropbox. Uploads from remote sources are handled server-to-server, so a 5 GB video won’t be eating into your mobile data plan. Files are removed from Uppy Server after an upload is complete, or after a reasonable timeout. Access tokens also don’t stick around for long, for security reasons.
Adding [Uppy Server](/docs/server/) to the mix enables remote sources such as Instagram, Google Drive, Dropbox, and direct urls. Uploads from remote sources are handled server-to-server, so a 5 GB video won’t be eating into your mobile data plan. Files are removed from Uppy Server after an upload is complete, or after a reasonable timeout. Access tokens also don’t stick around for long, for security reasons.

## Installation

Expand Down Expand Up @@ -61,8 +61,8 @@ Alternatively, you can also use a pre-built bundle from Transloadit's CDN: Edgly
``` html
<script>
var uppy = Uppy.Core({ autoProceed: false })
uppy.use(Uppy.DragDrop, {target: '.UppyDragDrop'})
uppy.use(Uppy.Tus, {endpoint: '//master.tus.io/files/'})
uppy.use(Uppy.DragDrop, { target: '#drag-drop-area' })
uppy.use(Uppy.Tus, { endpoint: 'https://master.tus.io/files/' })
uppy.run()
</script>
```
Expand All @@ -71,7 +71,7 @@ Alternatively, you can also use a pre-built bundle from Transloadit's CDN: Edgly

- [Uppy](/docs/uppy/) — full list of options, methods and events.
- [Plugins](/docs/plugins/) — list of Uppy plugins and their options.
- [Server](/docs/server/) — setting up and running an uppy-server instance, which adds support for Instagram, Dropbox, Google Drive and other remote sources.
- [Server](/docs/server/) — setting up and running an uppy-server instance, which adds support for Instagram, Dropbox, Google Drive, direct links, and other remote sources.
- [React](/docs/react/) — components to integrate uppy UI plugins with react apps.
- Architecture & Making a Plugin — how to write a plugin for Uppy [documentation in progress].

Expand All @@ -81,4 +81,4 @@ Alternatively, you can also use a pre-built bundle from Transloadit's CDN: Edgly
<img src="https://saucelabs.com/browser-matrix/transloadit-uppy.svg" alt="Sauce Test Status"/>
</a>

We aim to support IE10+ and recent versions of Safari, Edge, Chrome, Firefox and Opera.
We currently aim to support IE10+ and recent versions of Safari, Edge, Chrome, Firefox and Opera.
15 changes: 9 additions & 6 deletions website/src/docs/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Plugins are what makes Uppy useful: they help select, manipulate and upload file
- [Dashboard](/docs/dashboard) — full featured sleek UI with file previews, metadata editing, upload/pause/resume/cancel buttons and more. Includes `StatusBar` and `Informer` plugins by default
- [DragDrop](/docs/dragdrop) — plain and simple drag and drop area
- [FileInput](/docs/fileinput) — even more plain and simple, just a button
- [Provider Plugins](#provider-plugins) (remote sources that work through [Uppy Server](/docs/uppy-server/)): Instagram, GoogleDrive, Dropbox
- [Provider Plugins](#Provider-Plugins) (remote sources that work through [Uppy Server](/docs/uppy-server/)): Instagram, GoogleDrive, Dropbox, Url (direct link)
- [Webcam](/docs/webcam) — upload selfies or audio / video recordings
- **Uploaders:**
- [Tus](/docs/tus) — uploads using the [tus](https://tus.io) resumable upload protocol
Expand Down Expand Up @@ -93,19 +93,18 @@ See plugin documentation pages for other plugin-specific options.

## Provider Plugins

The Provider plugins help you connect to your accounts with remote file providers such as [Dropbox](https://dropbox.com), [Google Drive](https://drive.google.com), [Instagram](https://instagram.com). Because this requires server to server communication, they work tightly with [uppy-server](https://github.com/transloadit/uppy-server) to manage the server to server authroization for your account. Virtually most of the communication (file download/upload) is done on the server-to-server end, so this saves you the stress of data consumption on the client.
The Provider plugins help you connect to your accounts with remote file providers such as [Dropbox](https://dropbox.com), [Google Drive](https://drive.google.com), [Instagram](https://instagram.com) and remote urls (import a file by pasting a direct link to it). Because this requires server to server communication, they work tightly with [uppy-server](https://github.com/transloadit/uppy-server) to manage the server to server authroization for your account. Virtually most of the communication (file download/upload) is done on the server-to-server end, so this saves you the stress of data consumption on the client.

As of now, the supported providers are **Dropbox**, **GoogleDrive**, and **Instagram**.
As of now, the supported providers are **Dropbox**, **GoogleDrive**, **Instagram**, and **Url**.

Usage of the Provider plugins is not that different from any other *acquirer* plugin, except that it takes an extra option `host`, which specifies the url to your running `uppy-server`. This allows Uppy to know what server to connect to when server related operations are required by the provider plugin. Here's a quick example.

```js
const Uppy = require('uppy/lib/core')
const DragDrop = require('uppy/lib/plugins/Dashboard')
const Dashboard = require('uppy/lib/plugins/Dashboard')
const uppy = Uppy()
uppy.use(Dashboard, {
trigger: '#uppyModalOpener',
target: '#uppy',
trigger: '#pick-files'
})

// for Google Drive
Expand All @@ -119,4 +118,8 @@ uppy.use(Dropbox, {target: Dashboard, host: 'http://localhost:3020'})
// for Instagram
const Instagram = require('uppy/lib/plugins/Instagram')
uppy.use(Instagram, {target: Dashboard, host: 'http://localhost:3020'})

// for Url
const Url = require('uppy/lib/plugins/Url')
uppy.use(Url, {target: Dashboard, host: 'http://localhost:3020'})
```
1 change: 1 addition & 0 deletions website/src/docs/server.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ As of now uppy-server is integrated to work with:
- Google Drive
- Dropbox
- Instagram
- Remote Urls
- Amazon S3
- Local disk

Expand Down
9 changes: 4 additions & 5 deletions website/src/docs/uppy.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,15 @@ const uppy = Uppy({
onBeforeFileAdded: (currentFile, files) => Promise.resolve(),
onBeforeUpload: (files) => Promise.resolve(),
locale: defaultLocale,
store: new DefaultStore(),
thumbnailGeneration: true
store: new DefaultStore()
})
```

### `id: 'uppy'`

A site-wide unique ID for the instance.
If multiple Uppy instances are being used, for example on two different pages, an `id` should be specified.
This allows Uppy to store information in `localStorage` without colliding with other Uppy instances.

If multiple Uppy instances are being used, for example on two different pages, an `id` should be specified. This allows Uppy to store information in `localStorage` without colliding with other Uppy instances.

Note that this ID should be persistent across page reloads and navigation—it shouldn't be a random number that's different every time Uppy is loaded.
For example, if one Uppy instance is used to upload user avatars, and another to add photos to a blog post, you might use:
Expand Down Expand Up @@ -130,7 +129,7 @@ locale: {

We are using a forked [Polyglot.js](https://github.com/airbnb/polyglot.js/blob/master/index.js#L37-L60).

## `store: defaultStore()`
### `store: defaultStore()`

The Store to use to keep track of internal state. By default, a simple object is used.

Expand Down