UploadImage: Unsplash Panel

refs CORE-2626

Test Plan:
  - Start RCE API using the proper ENV variables, I can provide
    those upon request
  - Go to the Upload Image dialog
  - Click the Unsplash Panel
  - Type in a search phrase
  - You should be able to do a search and get results back
  - NOTE: At this point, you can't select an image and have
    it be inserted into the RCE

Change-Id: I06832be6ef1c2e299c531c68a8d34782c3cebee0
Reviewed-on: https://gerrit.instructure.com/195273
Tested-by: Jenkins
Reviewed-by: Ryan Shaw <ryan@instructure.com>
QA-Review: Ryan Shaw <ryan@instructure.com>
Product-Review: Clay Diffrient <cdiffrient@instructure.com>
This commit is contained in:
Clay Diffrient 2019-05-24 14:34:18 -06:00
parent 279d23b196
commit f8711628fc
11 changed files with 1037 additions and 15 deletions

View File

@ -113,6 +113,7 @@
"@instructure/ui-icons": "6",
"@instructure/ui-layout": "6.3.1-rc.1+2dd401cc",
"@instructure/ui-overlays": "6",
"@instructure/ui-pagination": "6",
"@instructure/ui-react-utils": "6",
"@instructure/ui-svg-images": "6",
"@instructure/ui-tabs": "6",
@ -127,6 +128,7 @@
"format-message": "^6",
"format-message-generate-id": "^6",
"isomorphic-fetch": "2.2.1",
"lodash": "^4",
"prop-types": "^15",
"react": "^0.14.8 || ^15.0.0 || ^16",
"react-dom": "^0.14.8 || ^15.0.0 || ^16",
@ -146,6 +148,7 @@
"@babel/register": "7",
"@instructure/babel-preset-pretranslated-format-message": "^1",
"@instructure/ui-babel-preset": "6",
"@testing-library/user-event": "^4.1.0",
"axe-testcafe": "^1.1.0",
"babel-loader": "^8.0.0",
"babel-plugin-dynamic-import-node": "^2.2.0",

View File

@ -20,12 +20,24 @@ import clickCallback from '../clickCallback'
import {getByLabelText} from 'react-testing-library'
describe('Instructure Image Plugin: clickCallback', () => {
let trayProps;
beforeEach(() => {
trayProps = {
source: {
initializeCollection () {},
initializeUpload () {},
initializeFlickr () {},
initializeImages() {},
initializeDocuments() {}
}
}
})
afterEach(() => {
document.querySelector('.canvas-rce-upload-container').remove()
})
it('adds the canvas-rce-upload-container element when opened', async () => {
await clickCallback({}, document)
await clickCallback({}, document, trayProps)
expect(document.querySelector('.canvas-rce-upload-container')).toBeTruthy()
})
@ -33,12 +45,12 @@ describe('Instructure Image Plugin: clickCallback', () => {
const container = document.createElement('div')
container.className = 'canvas-rce-upload-container'
document.body.appendChild(container)
await clickCallback({}, document)
await clickCallback({}, document, trayProps)
expect(document.querySelectorAll('.canvas-rce-upload-container').length).toEqual(1)
})
it('opens the UploadImage modal when called', async () => {
await clickCallback({}, document)
await clickCallback({}, document, trayProps)
expect(
getByLabelText(document, 'Upload Image', {
selector: 'form'

View File

@ -20,7 +20,7 @@ import React from 'react'
import ReactDOM from 'react-dom'
import formatMessage from '../../../format-message'
export default function(ed, document) {
export default function(ed, document, trayProps) {
return import('../shared/Upload/UploadFile').then(({UploadFile}) => {
let container = document.querySelector('.canvas-rce-upload-container')
if (!container) {
@ -39,8 +39,9 @@ export default function(ed, document) {
accept="image/*"
editor={ed}
label={formatMessage('Upload Image')}
panels={['COMPUTER', 'URL']}
panels={['COMPUTER', 'UNSPLASH', 'URL']}
onDismiss={handleDismiss}
trayProps={trayProps}
/>, container
)
})

View File

@ -0,0 +1,279 @@
/*
* Copyright (C) 2019 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, {useState, useEffect, useReducer, useRef, useCallback} from 'react'
import {string, func, object} from 'prop-types'
import {TextInput} from '@instructure/ui-text-input'
import {Flex} from '@instructure/ui-layout'
import {Img, Spinner} from '@instructure/ui-elements'
import {Pagination} from '@instructure/ui-pagination'
import {debounce} from 'lodash'
import formatMessage from '../../../../format-message'
import {StyleSheet, css} from 'aphrodite'
import UnsplashSVG from './UnsplashSVG'
const unsplashFetchReducer = (state, action) => {
switch (action.type) {
case 'FETCH':
return {...state, loading: true}
case 'FETCH_SUCCESS':
return {
...state,
loading: false,
totalPages: action.payload.total_pages,
results: {
...state.results,
...{[state.searchPage]: action.payload.results}
}
}
case 'FETCH_FAILURE':
return {...state, loading: false, error: true}
case 'SET_SEARCH_DATA': {
const newState = {...state, ...action.payload}
if (state.searchTerm !== action.payload.searchTerm) {
newState.results = {}
}
return newState
}
default:
throw new Error('Not implemented') // Should never get here.
}
}
const useUnsplashSearch = source => {
const [state, dispatch] = useReducer(unsplashFetchReducer, {
loading: false,
error: false,
results: {},
totalPages: 1,
searchTerm: '',
searchPage: 1
})
const effectFirstRun = useRef(true)
useEffect(() => {
const fetchData = () => {
dispatch({type: 'FETCH'})
source
.searchUnsplash(state.searchTerm, state.searchPage)
.then(results => {
dispatch({type: 'FETCH_SUCCESS', payload: results})
})
.catch(() => {
dispatch({type: 'FETCH_FAILURE'})
})
}
if (effectFirstRun.current) {
effectFirstRun.current = false
return
} else if (state.results[state.searchPage]) {
return // It's already in cache
} else {
fetchData()
}
}, [state.searchTerm, state.searchPage])
const search = (term, page) => {
dispatch({
type: 'SET_SEARCH_DATA',
payload: {
searchTerm: term,
searchPage: page
}
})
}
return {...state, search}
}
export default function UnsplashPanel({editor, source, imageUrl, setImageUrl}) {
const [page, setPage] = useState(1)
const [term, setTerm] = useState('')
const [selectedImage, setSelectedImage] = useState(null)
const [focusedImageIndex, setFocusedImageIndex] = useState(0)
const {totalPages, results, loading, search} = useUnsplashSearch(source)
const debouncedSearch = useCallback(debounce(search, 250), [])
const resultRefs = []
const skipEffect = useRef(false)
useEffect(() => {
if (skipEffect.current) {
skipEffect.current = false
return
}
if (resultRefs[focusedImageIndex]) {
resultRefs[focusedImageIndex].focus()
}
}, [focusedImageIndex])
return (
<>
<UnsplashSVG width="10em" />
<TextInput
type="search"
label={formatMessage('Search Term')}
value={term}
onChange={(e, val) => {
setFocusedImageIndex(0)
setTerm(val)
debouncedSearch(val, page)
}}
/>
{loading ? (
<Spinner
renderTitle={function() {
return formatMessage('Loading')
}}
size="large"
margin="0 0 0 medium"
/>
) : (
<>
<div
className={css(styles.container)}
role="radiogroup"
onBlur={e => {
if (!e.currentTarget.contains(e.relatedTarget)) {
let newIndex = 0
const selectedIndex = results[page].findIndex(result => result.id === selectedImage)
if (selectedIndex > 0) {
newIndex = selectedIndex
}
setFocusedImageIndex(newIndex)
skipEffect.current = true
}
}}
>
{results[page] &&
results[page].map((resultImage, index) => (
<div
ref={c => (resultRefs[index] = c)}
key={resultImage.id}
className={css(styles.imageContainer)}
role="radio"
aria-checked={resultImage.id === selectedImage}
tabIndex={index === focusedImageIndex ? 0 : -1}
onClick={() => {
setSelectedImage(resultImage.id)
let newIndex = 0
const selectedIndex = results[page].findIndex(
result => result.id === resultImage.id
)
if (selectedIndex > 0) {
newIndex = selectedIndex
}
setFocusedImageIndex(newIndex)
}}
onKeyDown={e => {
switch (e.keyCode) {
case 32: // Space
setSelectedImage(resultImage.id)
break
case 38: // Up
if (index - 1 < 0) {
setFocusedImageIndex(results[page].length - 1)
} else {
setFocusedImageIndex(index - 1)
}
break
case 40: // Down
if (index + 1 >= results[page].length) {
setFocusedImageIndex(0)
} else {
setFocusedImageIndex(index + 1)
}
break
default:
break
}
}}
>
<Img
src={resultImage.urls.thumbnail}
alt={resultImage.alt_text}
height="10em"
margin="xx-small"
/>
</div>
))}
</div>
{totalPages > 1 && results && Object.keys(results).length > 0 && (
<Flex as="div" width="100%" justifyItems="center" margin="small 0 small">
<Flex.Item margin="auto small auto small">
<Pagination
as="nav"
variant="compact"
labelNext={formatMessage('Next Page')}
labelPrev={formatMessage('Previous Page')}
>
{Array.from(Array(totalPages)).map((_v, i) => (
<Pagination.Page
key={i}
onClick={() => {
setPage(i + 1)
search(term, i + 1)
}}
current={i + 1 === page}
>
{i + 1}
</Pagination.Page>
))}
</Pagination>
</Flex.Item>
</Flex>
)}
<div>Current Selection is {selectedImage}</div>
</>
)}
</>
)
}
UnsplashPanel.propTypes = {
editor: object,
source: object,
imageUrl: string,
setImageUrl: func
}
export const styles = StyleSheet.create({
container: {
marginTop: '12px',
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
flexWrap: 'wrap',
flexFlow: 'row wrap'
},
imageContainer: {
width: 'auto',
height: '100%'
},
positionedText: {
position: 'absolute',
height: '100%',
width: '100%',
top: '0',
left: '0'
}
})

View File

@ -0,0 +1,27 @@
/*
* Copyright (C) 2019 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from 'react'
const UnsplashSVG = props => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 457.19 104.19" {...props}>
<path d="M59.88 38.66h27.53v48.75H0V38.66h27.53v24.37h32.35zm93 25c0 8.25-5.45 13.13-12.9 13.13-7.28 0-12.81-4.88-12.81-13.13V24.41h-12.22v39.13c0 15.45 11 25.21 25.06 25.21s25.15-9.76 25.15-25.21V24.41h-12.25zm43.7-21.13c-4.7 0-9.94 2-12.6 6.57v-5.41h-11.45v43.64h11.81v-25.1c0-5 3-9 8.16-9 5.68 0 8.08 3.82 8.08 8.7v25.4h11.8V59.82c.03-9.59-4.94-17.31-15.77-17.31zm43.31 18.37l-6.48-1.33c-2.47-.5-4-1.77-4-3.9 0-2.49 2.23-4.35 5.33-4.35 4.36 0 6.09 2.25 6.51 4.88h10.18c-.08-6-4.83-13.84-16.51-13.84-9.41 0-16.33 6.47-16.33 14.28 0 6.13 3.81 11.19 12.24 13l6.05 1.33c3.37.71 4.7 2.31 4.7 4.26 0 2.31-2.14 4.35-6 4.35-4.71 0-7.27-2.68-7.87-5.79h-10.5c.59 6.53 5.32 14.84 18.46 14.84 11.45 0 17.22-7.28 17.22-14.38-.01-6.36-4.36-11.59-12.97-13.37zm63.19 4.53c0 13.22-8.26 23-20.59 23-6 0-10.48-2.4-12.61-5.33v21.13h-11.8V43.67h11.45v5.41c2-3.37 6.83-6.39 13.4-6.39 12.81 0 20.18 9.76 20.18 22.72zm-11.63.09c0-7.72-4.79-12.25-10.83-12.25s-10.91 4.53-10.91 12.25 4.88 12.33 10.91 12.33 10.91-4.54 10.91-12.35zm68-21.83h11.45v43.64h-11.8v-5.31c-2 3.5-6.57 6.38-12.61 6.38-12.33 0-20.59-9.77-20.59-23 0-13 7.37-22.72 20.15-22.72 6.57 0 11.32 3.05 13.4 6.39zm-.18 21.83c0-7.72-4.88-12.25-10.91-12.25s-10.83 4.51-10.83 12.23 4.79 12.33 10.83 12.33 10.92-4.6 10.92-12.33zm-50.66 21.81h11.8V24.41h-11.8zm132.35-44.81c-4.17 0-9 1.41-11.81 4.78V24.41h-11.8v62.91h11.8V61.68c.27-4.8 3.2-8.52 8.17-8.52 5.68 0 8.08 3.83 8.07 8.71v25.47h11.81V59.82c-.01-9.59-5.15-17.3-16.24-17.3zm-42 18.36l-6.43-1.33c-2.47-.5-4-1.77-4-3.9 0-2.49 2.22-4.35 5.33-4.35 4.35 0 6.08 2.25 6.5 4.88h10.17c-.08-6-4.83-13.84-16.51-13.84-9.41 0-16.33 6.47-16.33 14.28 0 6.13 3.82 11.19 12.25 13l6 1.33c3.37.71 4.7 2.31 4.7 4.26 0 2.31-2.14 4.35-6 4.35-4.71 0-7.27-2.68-7.87-5.79h-10.49c.58 6.53 5.31 14.84 18.45 14.84 11.45 0 17.22-7.28 17.22-14.38 0-6.34-4.35-11.57-12.95-13.35zM59.88 0H27.53v24.37h32.35z"/>
</svg>
)
export default UnsplashSVG

View File

@ -28,10 +28,12 @@ import {isImage} from '../fileTypeUtils'
import indicate from '../../../../common/indicate'
import {StoreProvider} from '../../shared/StoreContext'
import RceApiSource from "../../../../sidebar/sources/api";
import Bridge from '../../../../bridge'
const ComputerPanel = React.lazy(() => import('./ComputerPanel'))
const UrlPanel = React.lazy(() => import('./UrlPanel'))
const UnsplashPanel = React.lazy(() => import('./UnsplashPanel'))
/**
* Handles uploading data based on what type of data is submitted.
@ -71,13 +73,20 @@ export const handleSubmit = (editor, accept, selectedPanel, uploadData, storePro
afterInsert()
}
export function UploadFile({accept, editor, label, panels, onDismiss, onSubmit = handleSubmit}) {
export function UploadFile({accept, editor, label, panels, onDismiss, trayProps, onSubmit = handleSubmit}) {
const [theFile, setFile] = useState(null)
const [hasUploadedFile, setHasUploadedFile] = useState(false)
const [fileUrl, setFileUrl] = useState('')
const [selectedPanel, setSelectedPanel] = useState(panels[0])
const [unsplashUrl, setUnsplashUrl] = useState('');
const trayProps = Bridge.trayProps.get(editor)
trayProps = trayProps || Bridge.trayProps.get(editor)
const source = trayProps.source || new RceApiSource({
jwt: trayProps.jwt,
refreshToken: trayProps.refreshToken,
host: trayProps.host
});
function renderTabs() {
return panels.map(panel => {
@ -99,7 +108,18 @@ export function UploadFile({accept, editor, label, panels, onDismiss, onSubmit =
</Tabs.Panel>
)
case 'UNSPLASH':
break;
return (
<Tabs.Panel key={panel} title='Unsplash'>
<Suspense fallback={<Spinner renderTitle={formatMessage('Loading')} size="large" />}>
<UnsplashPanel
editor={editor}
unsplashUrl={unsplashUrl}
setUnsplashUrl={setUnsplashUrl}
source={source}
/>
</Suspense>
</Tabs.Panel>
)
case 'URL':
return (
<Tabs.Panel key={panel} title={formatMessage('URL')}>
@ -157,6 +177,7 @@ UploadFile.propTypes = {
accept: oneOfType([arrayOf(string), string]),
editor: object.isRequired,
label: string.isRequired,
panels: arrayOf(oneOf(['COMPUTER', 'UNSPLASH', 'URL']))
panels: arrayOf(oneOf(['COMPUTER', 'UNSPLASH', 'URL'])),
trayProps: object
}

View File

@ -0,0 +1,367 @@
/*
* Copyright (C) 2019 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from 'react'
import {render, fireEvent, act, wait} from 'react-testing-library'
import userEvent from '@testing-library/user-event'
import UnsplashPanel from '../UnsplashPanel'
// Mock out the debounce to fire without debounce during tests.
jest.mock('lodash', () => ({debounce: jest.fn(fn => fn)}))
const getSampleUnsplashResults = () => ({
total_results: 2321,
total_pages: 194,
results: [
{
urls: {
link:
'https://images.unsplash.com/photo-1532386236358-a33d8a9434e3?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1532386236358-a33d8a9434e3?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: '1l2waV8glIQ',
alt_text: 'selective focus photography brown cat lying over black cat',
user: {
name: 'Raul Varzar',
avatar:
'https://images.unsplash.com/profile-1538941834664-a6d8eb80866b?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1479065476818-424362c3a854?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1479065476818-424362c3a854?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'Y_pLBbSAhHI',
alt_text: 'four brown tabby kittens',
user: {
name: "Q'AILA",
avatar:
'https://images.unsplash.com/profile-fb-1478804329-75cc0bd7b087.jpg?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1484733544471-3abf5846a4ff?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1484733544471-3abf5846a4ff?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'gAPXLS1LRVE',
alt_text: 'two short-fur orange cats lying on gray surface',
user: {
name: 'Olya Kuzovkina',
avatar:
'https://images.unsplash.com/profile-1484733460542-9653d0439bd9?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1555606396-79625d075363?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1555606396-79625d075363?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'jqhsi0NqdUI',
alt_text: 'person holding cat',
user: {
name: 'Tran Mau Tri Tam',
avatar:
'https://images.unsplash.com/profile-1527595925338-3e074feb55ce?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1559235038-1b0fadf76f78?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1559235038-1b0fadf76f78?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'MNju0A6EeE0',
alt_text: 'two silver tabby kittens',
user: {
name: 'Amy Baugess',
avatar:
'https://images.unsplash.com/profile-fb-1554227696-3afa4dab2fae.jpg?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1554181192-3ebfd857cc40?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1554181192-3ebfd857cc40?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: '4mA9_5vbZ_s',
alt_text: 'three cats beside road',
user: {
name: 'Yuliya Kosolapova',
avatar:
'https://images.unsplash.com/profile-1542573282965-bd0ef4147e78?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1554530700-747e22bb4e56?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1554530700-747e22bb4e56?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'bhO_wSXegfI',
alt_text: 'grey cat',
user: {
name: 'Sandy Millar',
avatar:
'https://images.unsplash.com/profile-1530245392659-56d20d09dfba?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1554146445-58ae3448247d?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1554146445-58ae3448247d?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'zgQXEtEnaxA',
alt_text: 'long-fur brown cat sitting on white desk',
user: {
name: 'Rikki Austin',
avatar:
'https://images.unsplash.com/profile-1542043341496-520a51bf0ccb?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1547239246-d2f052bdccf8?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1547239246-d2f052bdccf8?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'S10uzabOxr4',
alt_text: 'selective focus photography of gray cat beside window',
user: {
name: 'Rikki Austin',
avatar:
'https://images.unsplash.com/profile-1542043341496-520a51bf0ccb?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1550606873-e09a0d1a5a93?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1550606873-e09a0d1a5a93?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: '0vvwnuxvtnw',
alt_text: 'selective focus photography of short-fur black cat',
user: {
name: 'Maria Teneva',
avatar:
'https://images.unsplash.com/profile-fb-1540063787-b5d9329fee86.jpg?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1549221987-25a490f65d34?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1549221987-25a490f65d34?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'KWu_pl00QEQ',
alt_text: 'gray and brown cat near stairs',
user: {
name: 'Maria Teneva',
avatar:
'https://images.unsplash.com/profile-fb-1540063787-b5d9329fee86.jpg?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1557369560-a25f3fad22cf?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1557369560-a25f3fad22cf?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'TszVNhi39a8',
alt_text: null,
user: {
name: 'Karly Gomez',
avatar:
'https://images.unsplash.com/profile-1556908132245-1b888ce7e85d?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
}
]
})
describe('UnsplashPanel', () => {
it('fires off searches when the user types in the search box', () => {
const fakeSource = {
searchUnsplash: jest.fn().mockResolvedValue({})
}
const {getByLabelText} = render(<UnsplashPanel source={fakeSource} />)
const selectBox = getByLabelText('Search Term')
act(() => {
userEvent.type(selectBox, 'kittens')
})
expect(fakeSource.searchUnsplash).toHaveBeenCalled()
})
it('displays results after searching', async () => {
const fakeSource = {
searchUnsplash: jest.fn().mockResolvedValue(getSampleUnsplashResults())
}
const {getByLabelText, getByRole} = render(<UnsplashPanel source={fakeSource} />)
const selectBox = getByLabelText('Search Term')
act(() => {
userEvent.type(selectBox, 'kittens')
})
await wait(() => getByRole('radiogroup'))
const resultsContainer = getByRole('radiogroup')
expect(resultsContainer.children).toHaveLength(12)
})
it(
'shows pagination controls when there are more than one page of results', async () => {
const fakeSource = {
searchUnsplash: jest.fn().mockResolvedValue(getSampleUnsplashResults())
}
const {getByLabelText, getByText} = render(<UnsplashPanel source={fakeSource} />)
const selectBox = getByLabelText('Search Term')
act(() => {
userEvent.type(selectBox, 'kittens')
})
let nextPage
await wait(() => (nextPage = getByText('Next Page')))
expect(nextPage).toBeVisible()
}
)
it('does not show pagination when there is only one page of results', async () => {
const fakeResults = getSampleUnsplashResults()
fakeResults.total_pages = 1
const fakeSource = {
searchUnsplash: jest.fn().mockResolvedValue(fakeResults)
}
const {getByLabelText, queryByText} = render(<UnsplashPanel source={fakeSource} />)
const selectBox = getByLabelText('Search Term')
act(() => {
userEvent.type(selectBox, 'kittens')
})
let nextPage
await wait(() => (nextPage = queryByText('Next Page')))
expect(nextPage).toBeNull()
})
it('sends focus to the next result when pressing down', async () => {
const fakeResults = getSampleUnsplashResults()
const fakeSource = {
searchUnsplash: jest.fn().mockResolvedValue(fakeResults)
}
const {getByLabelText, getByRole, getAllByRole} = render(
<UnsplashPanel source={fakeSource} />
)
const selectBox = getByLabelText('Search Term')
act(() => {
userEvent.click(selectBox)
userEvent.type(selectBox, 'kittens')
})
await wait(() => getByRole('radio'))
const imageSelectors = getAllByRole('radio')
act(() => {
userEvent.click(imageSelectors[0])
fireEvent.keyDown(imageSelectors[0], {keyCode: 40})
})
expect(imageSelectors[1]).toHaveFocus()
})
it('sends focus to the previous element when pressing up', async () => {
const fakeResults = getSampleUnsplashResults()
const fakeSource = {
searchUnsplash: jest.fn().mockResolvedValue(fakeResults)
}
const {getByLabelText, getByRole, getAllByRole} = render(
<UnsplashPanel source={fakeSource} />
)
const selectBox = getByLabelText('Search Term')
act(() => {
userEvent.click(selectBox)
userEvent.type(selectBox, 'kittens')
})
await wait(() => getByRole('radio'))
const imageSelectors = getAllByRole('radio')
act(() => {
userEvent.click(imageSelectors[2])
fireEvent.keyDown(imageSelectors[2], {keyCode: 38})
})
expect(imageSelectors[1]).toHaveFocus()
})
it('sends focus to the first item when pressing down on the last item', async () => {
const fakeResults = getSampleUnsplashResults()
const fakeSource = {
searchUnsplash: jest.fn().mockResolvedValue(fakeResults)
}
const {getByLabelText, getByRole, getAllByRole} = render(
<UnsplashPanel source={fakeSource} />
)
const selectBox = getByLabelText('Search Term')
act(() => {
userEvent.click(selectBox)
userEvent.type(selectBox, 'kittens')
})
await wait(() => getByRole('radio'))
const imageSelectors = getAllByRole('radio')
act(() => {
userEvent.click(imageSelectors[11])
})
act(() => {
fireEvent.keyDown(imageSelectors[11], {keyCode: 40})
})
expect(imageSelectors[0]).toHaveFocus()
})
it('sends focus to the last element when pressing up on the first item', async () => {
const fakeResults = getSampleUnsplashResults()
const fakeSource = {
searchUnsplash: jest.fn().mockResolvedValue(fakeResults)
}
const {getByLabelText, getByRole, getAllByRole} = render(
<UnsplashPanel source={fakeSource} />
)
const selectBox = getByLabelText('Search Term')
act(() => {
userEvent.click(selectBox)
userEvent.type(selectBox, 'kittens')
})
await wait(() => getByRole('radio'))
const imageSelectors = getAllByRole('radio')
act(() => {
userEvent.click(imageSelectors[0])
})
act(() => {
fireEvent.keyDown(imageSelectors[0], {keyCode: 38})
})
expect(imageSelectors[11]).toHaveFocus()
});
it.todo('selects an image when pressing spacebar')
})

View File

@ -21,10 +21,28 @@ import {render, fireEvent} from 'react-testing-library'
import {UploadFile, handleSubmit} from '../UploadFile'
describe('UploadFile', () => {
let trayProps;
let fakeEditor;
beforeEach(() => {
trayProps = {
source: {
initializeCollection () {},
initializeUpload () {},
initializeFlickr () {},
initializeImages() {},
initializeDocuments() {}
}
}
fakeEditor = {}
})
afterEach(() => {
trayProps = null
fakeEditor = null
})
it('calls onDismiss prop when closing', () => {
const handleDismiss = jest.fn()
const {getByText} = render(
<UploadFile onDismiss={handleDismiss} panels={['COMPUTER', 'URL']} />
<UploadFile label="Test" editor={fakeEditor} trayProps={trayProps} onDismiss={handleDismiss} panels={['COMPUTER', 'URL']} />
)
const closeBtn = getByText('Close')
@ -36,7 +54,7 @@ describe('UploadFile', () => {
const handleSubmit = jest.fn()
const handleDismiss = () => {}
const {getByText} = render(
<UploadFile onDismiss={handleDismiss} onSubmit={handleSubmit} panels={['COMPUTER', 'URL']} />
<UploadFile label="Test" editor={fakeEditor} trayProps={trayProps} onDismiss={handleDismiss} onSubmit={handleSubmit} panels={['COMPUTER', 'URL']} />
)
const submitBtn = getByText('Submit').closest('button')
fireEvent.click(submitBtn)
@ -47,6 +65,9 @@ describe('UploadFile', () => {
it('adds computer and url panels', () => {
const {getByLabelText} = render(
<UploadFile
label="Test"
editor={fakeEditor}
trayProps={trayProps}
onDismiss={() => {}}
panels={['COMPUTER', 'URL']}
/>
@ -59,6 +80,9 @@ describe('UploadFile', () => {
it('adds only the computer panel', () => {
const {getByLabelText, queryByLabelText} = render(
<UploadFile
label="Test"
editor={fakeEditor}
trayProps={trayProps}
onDismiss={() => {}}
panels={['COMPUTER']}
/>

View File

@ -277,6 +277,13 @@ class RceApiSource {
return this.apiFetch(uri, headers)
}
searchUnsplash(term, page) {
let headers = headerFor(this.jwt)
let base = this.baseUri('unsplash/search')
let uri = `${base}?term=${encodeURIComponent(term)}&page=${page}&per_page=12`
return this.apiFetch(uri, headers)
}
getFile(id) {
let headers = headerFor(this.jwt)
let base = this.baseUri('file')

View File

@ -330,6 +330,237 @@ const DOCUMENTS = {
}
}
const UNSPLASH_RESULTS = {
kittens1: {
total_results: 2,
total_pages: 1,
results: [
{
urls: {
link:
'https://images.unsplash.com/photo-1479065476818-424362c3a854?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1479065476818-424362c3a854?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'Y_pLBbSAhHI',
alt_text: 'four brown tabby kittens',
user: {
name: "Q'AILA",
avatar:
'https://images.unsplash.com/profile-fb-1478804329-75cc0bd7b087.jpg?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1484733544471-3abf5846a4ff?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1484733544471-3abf5846a4ff?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'gAPXLS1LRVE',
alt_text: 'two short-fur orange cats lying on gray surface',
user: {
name: 'Olya Kuzovkina',
avatar:
'https://images.unsplash.com/profile-1484733460542-9653d0439bd9?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
}
]
},
kittens2: {
total_results: '3',
total_pages: 2,
results: [
{
urls: {
link:
'https://images.unsplash.com/photo-1554530700-747e22bb4e56?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1554530700-747e22bb4e56?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'bhO_wSXegfI',
alt_text: 'grey cat',
user: {
name: 'Sandy Millar',
avatar:
'https://images.unsplash.com/profile-1530245392659-56d20d09dfba?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1548878811-cddbc06f9d4c?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1548878811-cddbc06f9d4c?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: '2qzT9qKvI9U',
alt_text: 'brown tabby cat',
user: {
name: 'Sandy Millar',
avatar:
'https://images.unsplash.com/profile-1530245392659-56d20d09dfba?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
}
]
},
kittens3: {
total_results: 2009,
total_pages: 201,
results: [
{
urls: {
link:
'https://images.unsplash.com/photo-1479065476818-424362c3a854?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1479065476818-424362c3a854?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'Y_pLBbSAhHI',
alt_text: 'four brown tabby kittens',
user: {
name: "Q'AILA",
avatar:
'https://images.unsplash.com/profile-fb-1478804329-75cc0bd7b087.jpg?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1484733544471-3abf5846a4ff?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1484733544471-3abf5846a4ff?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'gAPXLS1LRVE',
alt_text: 'two short-fur orange cats lying on gray surface',
user: {
name: 'Olya Kuzovkina',
avatar:
'https://images.unsplash.com/profile-1484733460542-9653d0439bd9?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1554530700-747e22bb4e56?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1554530700-747e22bb4e56?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'bhO_wSXegfI',
alt_text: 'grey cat',
user: {
name: 'Sandy Millar',
avatar:
'https://images.unsplash.com/profile-1530245392659-56d20d09dfba?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1548878811-cddbc06f9d4c?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1548878811-cddbc06f9d4c?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: '2qzT9qKvI9U',
alt_text: 'brown tabby cat',
user: {
name: 'Sandy Millar',
avatar:
'https://images.unsplash.com/profile-1530245392659-56d20d09dfba?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1554146445-58ae3448247d?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1554146445-58ae3448247d?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'zgQXEtEnaxA',
alt_text: 'long-fur brown cat sitting on white desk',
user: {
name: 'Rikki Austin',
avatar:
'https://images.unsplash.com/profile-1542043341496-520a51bf0ccb?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1547239246-d2f052bdccf8?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1547239246-d2f052bdccf8?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'S10uzabOxr4',
alt_text: 'selective focus photography of gray cat beside window',
user: {
name: 'Rikki Austin',
avatar:
'https://images.unsplash.com/profile-1542043341496-520a51bf0ccb?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1520811607976-6d7812b0ecac?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1520811607976-6d7812b0ecac?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: '2Cl0lX_4bag',
alt_text: 'two gray and black cats eating food on white plastic pet bowl',
user: {
name: 'Bonnie Kittle',
avatar:
'https://images.unsplash.com/profile-1520272805752-525f71e721ca?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1532386236358-a33d8a9434e3?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1532386236358-a33d8a9434e3?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: '1l2waV8glIQ',
alt_text: 'selective focus photography brown cat lying over black cat',
user: {
name: 'Raul Varzar',
avatar:
'https://images.unsplash.com/profile-1538941834664-a6d8eb80866b?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1554181192-3ebfd857cc40?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1554181192-3ebfd857cc40?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: '4mA9_5vbZ_s',
alt_text: 'three cats beside road',
user: {
name: 'Yuliya Kosolapova',
avatar:
'https://images.unsplash.com/profile-1542573282965-bd0ef4147e78?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
},
{
urls: {
link:
'https://images.unsplash.com/photo-1557369560-a25f3fad22cf?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ',
thumbnail:
'https://images.unsplash.com/photo-1557369560-a25f3fad22cf?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjY4MTA0fQ'
},
id: 'TszVNhi39a8',
alt_text: null,
user: {
name: 'Karly Gomez',
avatar:
'https://images.unsplash.com/profile-1556908132245-1b888ce7e85d?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32'
}
}
]
}
}
export function getSession() {
return Promise.resolve({
contextType: "course",
@ -473,6 +704,18 @@ export function searchFlickr(term) {
});
}
export function searchUnsplash(term) {
return new Promise(function (resolve, reject) {
setTimeout(() => {
if (UNSPLASH_RESULTS[term]) {
resolve(UNSPLASH_RESULTS[term])
} else {
reject('No search results!')
}
}, 1000)
})
}
export function setUsageRights(id, usageRights) {
const msg = "Setting the following usage rights for file (id: %s):";
console.log(msg, id, usageRights); // eslint-disable-line no-console
@ -503,4 +746,4 @@ export function fetchDocs(bookmark) {
}
}, FAKE_TIMEOUT)
});
}
}

View File

@ -776,7 +776,7 @@
pirates "^4.0.0"
source-map-support "^0.5.9"
"@babel/runtime@^7", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.3":
"@babel/runtime@^7", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.3", "@babel/runtime@^7.4.5":
version "7.4.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.5.tgz#582bb531f5f9dc67d2fcb682979894f75e253f12"
integrity sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==
@ -1914,6 +1914,27 @@
no-scroll "^2.1.0"
prop-types "^15"
"@instructure/ui-pagination@6":
version "6.2.0"
resolved "https://registry.yarnpkg.com/@instructure/ui-pagination/-/ui-pagination-6.2.0.tgz#fa66daa076a54c97882839b9086ff2f9677e4421"
integrity sha512-rKMPi2VXsnzOYuJERMPbMOG2jomPhxXjv3m8eaVKlKv/Sn5vPwj85Ngjcb3Uf/qR/vbjzO+3TPRlTSXinPA3Pw==
dependencies:
"@babel/runtime" "^7"
"@instructure/ui-a11y" "^6.2.0"
"@instructure/ui-buttons" "^6.2.0"
"@instructure/ui-elements" "^6.2.0"
"@instructure/ui-icons" "^6.2.0"
"@instructure/ui-layout" "^6.2.0"
"@instructure/ui-overlays" "^6.2.0"
"@instructure/ui-portal" "^6.2.0"
"@instructure/ui-prop-types" "^6.2.0"
"@instructure/ui-react-utils" "^6.2.0"
"@instructure/ui-testable" "^6.2.0"
"@instructure/ui-themeable" "^6.2.0"
"@instructure/ui-utils" "^6.2.0"
"@instructure/uid" "^6.2.0"
prop-types "^15"
"@instructure/ui-pagination@^5", "@instructure/ui-pagination@^5.52.3":
version "5.52.3"
resolved "https://registry.yarnpkg.com/@instructure/ui-pagination/-/ui-pagination-5.52.3.tgz#05664416493852f50356eb283f700958ee87e142"
@ -2629,6 +2650,23 @@
resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5"
integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==
"@testing-library/dom@5.1.1":
version "5.1.1"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-5.1.1.tgz#091a30b1ca058080bf432cd1aeb2b7c646022f97"
integrity sha512-twpAkqomsI0xeOLehijOAmPxeKvs6+WZC/6/nXD0+HNQupP3OZeZho/PBlNhrGL+8nQWiPjdvmxeyU0tq+hctA==
dependencies:
"@babel/runtime" "^7.4.5"
"@sheerun/mutationobserver-shim" "^0.3.2"
pretty-format "^24.8.0"
wait-for-expect "^1.2.0"
"@testing-library/user-event@^4.1.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-4.1.0.tgz#f039fc10b2c5f7dfd82896e25450a86e3b05684b"
integrity sha512-INS0lbelHSlYmaZi78XTXghvwqi1J9S2SSYgvKKdMhzI479Z5mW5oGDCguePU+KwHY5pAXTHZKmweQBeQ5IaSA==
dependencies:
"@testing-library/dom" "5.1.1"
"@tinymce/tinymce-react@^3.0.1":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@tinymce/tinymce-react/-/tinymce-react-3.1.1.tgz#13ca3f988cbe6bfb9c67649ae6f986648b73aa73"
@ -15807,7 +15845,7 @@ prop-types-exact@^1.2.0:
object.assign "^4.1.0"
reflect.ownkeys "^0.2.0"
"prop-types@>= 15.7.0", prop-types@^15, prop-types@^15.5.10, prop-types@^15.5.6, prop-types@^15.5.8, prop-types@^15.5.9, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
"prop-types@>= 15.7.0", prop-types@^15, prop-types@^15.5.10, prop-types@^15.5.6, prop-types@^15.5.8, prop-types@^15.5.9, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@~15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@ -19734,7 +19772,7 @@ waait@^1:
resolved "https://registry.yarnpkg.com/waait/-/waait-1.0.4.tgz#1d177bab3175bfb56f0f832526582e0ca0b2650d"
integrity sha512-fMUqZH5xkzDgzw3b0CzOq7IBjIx9ig09gnpnRpRgonbPOZJWGURXWWHWt3xJa8cpxjh1WGFzRAD96V8i2C8Wmg==
wait-for-expect@^1.1.1:
wait-for-expect@^1.1.1, wait-for-expect@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/wait-for-expect/-/wait-for-expect-1.2.0.tgz#fdab6a26e87d2039101db88bff3d8158e5c3e13f"
integrity sha512-EJhKpA+5UHixduMBEGhTFuLuVgQBKWxkFbefOdj2bbk2/OpA5Opsc4aUTGmF+qJ+v3kTGxDRNYwKaT4j6g5n8Q==