Skip to content

Commit

Permalink
Make @uppy/unsplash production ready (#3196)
Browse files Browse the repository at this point in the history
Co-authored-by: Alexander Zaytsev <nqst@users.noreply.github.com>
Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
  • Loading branch information
3 people committed Oct 1, 2021
1 parent e435f4a commit b7559ac
Show file tree
Hide file tree
Showing 15 changed files with 664 additions and 460 deletions.
Expand Up @@ -49,3 +49,7 @@ exports.getNextPageQuery = (currentQuery) => {
delete query.q
return querystring.stringify(query)
}

exports.getAuthor = (item) => {
return { name: item.user.name, url: item.user.links.html }
}
108 changes: 57 additions & 51 deletions packages/@uppy/companion/src/server/provider/unsplash/index.js
Expand Up @@ -7,6 +7,33 @@ const { ProviderApiError } = require('../error')

const BASE_URL = 'https://api.unsplash.com'

function adaptData (body, currentQuery) {
const pagesCount = body.total_pages
const currentPage = Number(currentQuery.cursor || 1)
const hasNextPage = currentPage < pagesCount
const subList = adapter.getItemSubList(body) || []

return {
searchedFor: currentQuery.q,
username: null,
items: subList.map((item) => ({
isFolder: adapter.isFolder(item),
icon: adapter.getItemIcon(item),
name: adapter.getItemName(item),
mimeType: adapter.getMimeType(item),
id: adapter.getItemId(item),
thumbnail: adapter.getItemThumbnailUrl(item),
requestPath: adapter.getItemRequestPath(item),
modifiedDate: adapter.getItemModifiedDate(item),
author: adapter.getAuthor(item),
size: null,
})),
nextPageQuery: hasNextPage
? adapter.getNextPageQuery(currentQuery)
: null,
}
}

/**
* Adapter for API https://api.unsplash.com
*/
Expand All @@ -31,11 +58,11 @@ class Unsplash extends SearchProvider {

request(reqOpts, (err, resp, body) => {
if (err || resp.statusCode !== 200) {
err = this._error(err, resp)
logger.error(err, 'provider.unsplash.list.error')
return done(err)
const error = this.error(err, resp)
logger.error(error, 'provider.unsplash.list.error')
return done(error)
}
done(null, this.adaptData(body, query))
return done(null, adaptData(body, query))
})
}

Expand All @@ -48,28 +75,33 @@ class Unsplash extends SearchProvider {
Authorization: `Client-ID ${token}`,
},
}

request(reqOpts, (err, resp, body) => {
if (err || resp.statusCode !== 200) {
err = this._error(err, resp)
logger.error(err, 'provider.unsplash.download.error')
onData(err)
const error = this.error(err, resp)
logger.error(error, 'provider.unsplash.download.error')
onData(error)
return
}

const url = body.links.download
request.get(url)
.on('response', (resp) => {
if (resp.statusCode !== 200) {
onData(this._error(null, resp))

request
.get(url)
.on('response', (response) => {
if (response.statusCode !== 200) {
onData(this.error(null, response))
} else {
resp.on('data', (chunk) => onData(null, chunk))
response.on('data', (chunk) => onData(null, chunk))
}
})
.on('end', () => onData(null, null))
.on('error', (err) => {
logger.error(err, 'provider.unsplash.download.url.error')
onData(err)
// To attribute the author of the image, we call the `download_location`
// endpoint to increment the download count on Unsplash.
// https://help.unsplash.com/en/articles/2511258-guideline-triggering-a-download
.on('complete', () => request({ ...reqOpts, url: body.links.download_location }))
.on('error', (error) => {
logger.error(error, 'provider.unsplash.download.url.error')
onData(error)
})
})
}
Expand All @@ -86,53 +118,27 @@ class Unsplash extends SearchProvider {

request(reqOpts, (err, resp, body) => {
if (err || resp.statusCode !== 200) {
err = this._error(err, resp)
logger.error(err, 'provider.unsplash.size.error')
done(err)
const error = this.error(err, resp)
logger.error(error, 'provider.unsplash.size.error')
done(error)
return
}

getURLMeta(body.links.download)
.then(({ size }) => done(null, size))
.catch((err) => {
logger.error(err, 'provider.unsplash.size.error')
.catch((error) => {
logger.error(error, 'provider.unsplash.size.error')
done()
})
})
}

adaptData (body, currentQuery) {
const data = {
searchedFor: currentQuery.q,
username: null,
items: [],
}
const items = adapter.getItemSubList(body)
items.forEach((item) => {
data.items.push({
isFolder: adapter.isFolder(item),
icon: adapter.getItemIcon(item),
name: adapter.getItemName(item),
mimeType: adapter.getMimeType(item),
id: adapter.getItemId(item),
thumbnail: adapter.getItemThumbnailUrl(item),
requestPath: adapter.getItemRequestPath(item),
modifiedDate: adapter.getItemModifiedDate(item),
size: null,
})
})

const pagesCount = body.total_pages
const currentPage = parseInt(currentQuery.cursor || 1)
const hasNextPage = currentPage < pagesCount
data.nextPageQuery = hasNextPage ? adapter.getNextPageQuery(currentQuery) : null
return data
}

_error (err, resp) {
// eslint-disable-next-line class-methods-use-this
error (err, resp) {
if (resp) {
const fallbackMessage = `request to Unsplash returned ${resp.statusCode}`
const msg = resp.body && resp.body.errors ? `${resp.body.errors}` : fallbackMessage
const msg
= resp.body && resp.body.errors ? `${resp.body.errors}` : fallbackMessage
return new ProviderApiError(msg, resp.statusCode)
}

Expand Down
98 changes: 63 additions & 35 deletions packages/@uppy/dashboard/src/components/FileItem/FileInfo/index.js
@@ -1,51 +1,75 @@
const { h } = require('preact')
const { h, Fragment } = require('preact')
const prettierBytes = require('@transloadit/prettier-bytes')
const truncateString = require('@uppy/utils/lib/truncateString')

const renderFileName = (props) => {
// Take up at most 2 lines on any screen
let maxNameLength
// For very small mobile screens
if (props.containerWidth <= 352) {
maxNameLength = 35
// For regular mobile screens
} else if (props.containerWidth <= 576) {
maxNameLength = 60
// For desktops
} else {
maxNameLength = 30
const { author, name } = props.file.meta

function getMaxNameLength () {
if (props.containerWidth <= 352) {
return 35
}
if (props.containerWidth <= 576) {
return 60
}
// When `author` is present, we want to make sure
// the file name fits on one line so we can place
// the author on the second line.
return author ? 20 : 30
}

return (
<div className="uppy-Dashboard-Item-name" title={props.file.meta.name}>
{truncateString(props.file.meta.name, maxNameLength)}
<div className="uppy-Dashboard-Item-name" title={name}>
{truncateString(name, getMaxNameLength())}
</div>
)
}

const renderFileSize = (props) => (
props.file.size
&& (
<div className="uppy-Dashboard-Item-statusSize">
{prettierBytes(props.file.size)}
const renderAuthor = (props) => {
const { author } = props.file.meta
const { providerName } = props.file.remote
const dot = `\u00B7`

if (!author) {
return null
}

return (
<div className="uppy-Dashboard-Item-author">
<a
href={`${author.url}?utm_source=Companion&utm_medium=referral`}
target="_blank"
rel="noopener noreferrer"
>
{truncateString(author.name, 13)}
</a>
{providerName ? (
<Fragment>
{` ${dot} `}
{providerName}
</Fragment>
) : null}
</div>
)
)
}

const renderFileSize = (props) => props.file.size && (
<div className="uppy-Dashboard-Item-statusSize">
{prettierBytes(props.file.size)}
</div>
)

const ReSelectButton = (props) => (
props.file.isGhost
&& (
<span>
{' \u2022 '}
<button
className="uppy-u-reset uppy-c-btn uppy-Dashboard-Item-reSelect"
type="button"
onClick={props.toggleAddFilesPanel}
>
{props.i18n('reSelect')}
</button>
</span>
)
const ReSelectButton = (props) => props.file.isGhost && (
<span>
{' \u2022 '}
<button
className="uppy-u-reset uppy-c-btn uppy-Dashboard-Item-reSelect"
type="button"
onClick={props.toggleAddFilesPanel}
>
{props.i18n('reSelect')}
</button>
</span>
)

const ErrorButton = ({ file, onClick }) => {
Expand All @@ -68,10 +92,14 @@ const ErrorButton = ({ file, onClick }) => {

module.exports = function FileInfo (props) {
return (
<div className="uppy-Dashboard-Item-fileInfo" data-uppy-file-source={props.file.source}>
<div
className="uppy-Dashboard-Item-fileInfo"
data-uppy-file-source={props.file.source}
>
{renderFileName(props)}
<div className="uppy-Dashboard-Item-status">
{renderFileSize(props)}
{renderAuthor(props)}
{ReSelectButton(props)}
<ErrorButton
file={props.file}
Expand Down
Expand Up @@ -17,6 +17,19 @@
}
}

.uppy-Dashboard-Item-author {
color: $gray-600;
vertical-align: bottom;
font-size: 11px;
font-weight: normal;
display: inline-block;
line-height: 1;

a {
color: $gray-600;
}
}

.uppy-Dashboard-Item-status {
color: $gray-600;
font-weight: normal;
Expand Down

0 comments on commit b7559ac

Please sign in to comment.