show saved buttons and icons in rce tray
closes MAT-185 flag=rce_buttons_and_icons Test Plan - Create many (ideally 25+) Buttons and Icons. - Open the Saved Buttons and Icons tray. - Verify that the Buttons and Icons appear. - Verify that pagination works (paginates at 25). - Verify that filtering by a search string works. - Verify that sorting by date works. - Verify that sorting alphabetically works. - Verify that switching to another Tray type and back works. Change-Id: Ie4fec38cca8cb827c23b4ce044beb67809df7216 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/271811 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Product-Review: David Lyons <lyons@instructure.com> Reviewed-by: Weston Dransfield <wdransfield@instructure.com> QA-Review: Weston Dransfield <wdransfield@instructure.com>
This commit is contained in:
parent
cc27686aeb
commit
a13867e00f
|
@ -22,7 +22,7 @@ import ReactDOM from 'react-dom'
|
|||
import bridge from '../../../bridge'
|
||||
import {StoreProvider} from '../shared/StoreContext'
|
||||
|
||||
export default function (ed, document, type) {
|
||||
export default function (ed, document) {
|
||||
return import('./components/ButtonsTray').then(({ButtonsTray}) => {
|
||||
let container = document.querySelector('#instructure-rce-buttons-tray-container')
|
||||
const trayProps = bridge.trayProps.get(ed)
|
||||
|
@ -40,7 +40,7 @@ export default function (ed, document, type) {
|
|||
|
||||
ReactDOM.render(
|
||||
<StoreProvider {...trayProps}>
|
||||
{() => <ButtonsTray editor={ed} onUnmount={handleUnmount} type={type} />}
|
||||
{() => <ButtonsTray editor={ed} onUnmount={handleUnmount} />}
|
||||
</StoreProvider>,
|
||||
container
|
||||
)
|
||||
|
|
|
@ -25,15 +25,11 @@ import {Tray} from '@instructure/ui-tray'
|
|||
import formatMessage from '../../../../format-message'
|
||||
import {getTrayHeight} from '../../shared/trayUtils'
|
||||
import {CreateButtonForm} from './CreateButtonForm'
|
||||
import {SavedButtonList} from './SavedButtonList'
|
||||
|
||||
export function ButtonsTray({editor, onUnmount, type}) {
|
||||
export function ButtonsTray({editor, onUnmount}) {
|
||||
const [isOpen, setIsOpen] = useState(true)
|
||||
|
||||
const title =
|
||||
type === 'create'
|
||||
? formatMessage('Buttons and Icons')
|
||||
: formatMessage('Saved Buttons and Icons')
|
||||
const title = formatMessage('Buttons and Icons')
|
||||
|
||||
return (
|
||||
<Tray
|
||||
|
@ -62,12 +58,8 @@ export function ButtonsTray({editor, onUnmount, type}) {
|
|||
</Flex>
|
||||
</Flex.Item>
|
||||
|
||||
<Flex.Item as="content" padding="small">
|
||||
{type === 'create' ? (
|
||||
<CreateButtonForm editor={editor} onClose={() => setIsOpen(false)} />
|
||||
) : (
|
||||
<SavedButtonList />
|
||||
)}
|
||||
<Flex.Item as="slot" padding="small">
|
||||
<CreateButtonForm editor={editor} onClose={() => setIsOpen(false)} />
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Tray>
|
||||
|
|
|
@ -16,6 +16,95 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export const SavedButtonList = () => {
|
||||
return null
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import {func, shape, string} from 'prop-types';
|
||||
|
||||
import Images from '../../instructure_image/Images'
|
||||
|
||||
export function rceToFile({createdAt, id, name, thumbnailUrl, type, url}) {
|
||||
return {
|
||||
content_type: type,
|
||||
date: createdAt,
|
||||
display_name: name,
|
||||
filename: name,
|
||||
href: url,
|
||||
id,
|
||||
thumbnail_url: thumbnailUrl
|
||||
}
|
||||
}
|
||||
|
||||
const SavedButtonList = ({context, onImageEmbed, searchString, sortBy, source}) => {
|
||||
const [buttonsAndIconsBookmark, setButtonsAndIconsBookmark] = useState(null)
|
||||
const [buttonsAndIcons, setButtonsAndIcons] = useState([])
|
||||
const [hasMore, setHasMore] = useState(true)
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
|
||||
const resetState = () => {
|
||||
setButtonsAndIconsBookmark(null)
|
||||
setButtonsAndIcons([])
|
||||
setHasMore(true)
|
||||
setIsLoading(true)
|
||||
}
|
||||
|
||||
const onLoadedImages = ({bookmark, files}) => {
|
||||
setButtonsAndIconsBookmark(bookmark)
|
||||
setHasMore(bookmark !== null)
|
||||
setIsLoading(false)
|
||||
|
||||
setButtonsAndIcons(prevButtonsAndIcons => [
|
||||
...prevButtonsAndIcons,
|
||||
...files
|
||||
.filter(({type}) => type === 'image/svg+xml')
|
||||
.map(rceToFile)
|
||||
])
|
||||
}
|
||||
|
||||
const fetchButtonsAndIcons = bookmark => {
|
||||
setIsLoading(true)
|
||||
source.fetchButtonsAndIcons(
|
||||
{contextId: context.id, contextType: context.type},
|
||||
bookmark,
|
||||
searchString,
|
||||
sortBy,
|
||||
onLoadedImages
|
||||
)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
resetState()
|
||||
}, [searchString, sortBy.order, sortBy.sort])
|
||||
|
||||
return (
|
||||
<Images
|
||||
contextType={context.type}
|
||||
fetchInitialImages={() => {
|
||||
fetchButtonsAndIcons()
|
||||
}}
|
||||
fetchNextImages={() => {
|
||||
fetchButtonsAndIcons(buttonsAndIconsBookmark)
|
||||
}}
|
||||
images={{[context.type]: {error: null, files: buttonsAndIcons, hasMore, isLoading}}}
|
||||
onImageEmbed={onImageEmbed}
|
||||
searchString={searchString}
|
||||
sortBy={sortBy}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
SavedButtonList.propTypes = {
|
||||
context: shape({
|
||||
id: string.isRequired,
|
||||
type: string.isRequired,
|
||||
}),
|
||||
onImageEmbed: func.isRequired,
|
||||
searchString: string,
|
||||
sortBy: shape({
|
||||
order: string,
|
||||
sort: string
|
||||
}),
|
||||
source: shape({
|
||||
fetchButtonsAndIcons: func.isRequired
|
||||
})
|
||||
}
|
||||
|
||||
export default SavedButtonList
|
||||
|
|
|
@ -42,11 +42,6 @@ describe('RCE "Buttons and Icons" Plugin > ButtonsTray', () => {
|
|||
screen.getByRole('heading', {name: /buttons and icons/i})
|
||||
})
|
||||
|
||||
it('renders the list view', () => {
|
||||
renderComponent({...defaults, type: 'list'})
|
||||
screen.getByRole('heading', {name: /saved buttons and icons/i})
|
||||
})
|
||||
|
||||
it('closes the tray', async () => {
|
||||
const onUnmount = jest.fn()
|
||||
renderComponent({...defaults, onUnmount})
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright (C) 2021 - 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, waitFor} from '@testing-library/react'
|
||||
import sinon from 'sinon'
|
||||
|
||||
import RceApiSource from '../../../../../sidebar/sources/api'
|
||||
|
||||
import SavedButtonList from '../SavedButtonList'
|
||||
import {rceToFile} from '../SavedButtonList'
|
||||
|
||||
describe('RCE "Buttons and Icons" Plugin > SavedButtonList', () => {
|
||||
let defaultProps, fetchPageStub, globalFetchStub
|
||||
|
||||
const apiSource = new RceApiSource({
|
||||
alertFunc: () => {},
|
||||
jwt: 'theJWT'
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
globalFetchStub = sinon.stub(global, 'fetch')
|
||||
const context = {id: '101', type: 'course'}
|
||||
const buttonsAndIconsFolder = {filesUrl: 'http://rce.example.com/api/folders/52', id: '1'}
|
||||
const buttonAndIcon = {
|
||||
createdAt: '',
|
||||
id: 1,
|
||||
name: 'button.svg',
|
||||
thumbnailUrl: '',
|
||||
type: 'image/svg+xml',
|
||||
url: ''
|
||||
}
|
||||
const otherImage = {
|
||||
createdAt: '',
|
||||
id: 2,
|
||||
name: 'screenshot.jpg',
|
||||
thumbnailUrl: '',
|
||||
type: 'image/jpeg',
|
||||
url: ''
|
||||
}
|
||||
const folders = [buttonsAndIconsFolder]
|
||||
|
||||
fetchPageStub = sinon.stub(apiSource, 'fetchPage')
|
||||
fetchPageStub
|
||||
.withArgs(`/api/folders/buttons_and_icons?contextType=course&contextId=${context.id}`)
|
||||
.returns(Promise.resolve({folders}))
|
||||
|
||||
fetchPageStub
|
||||
.withArgs(
|
||||
'http://rce.example.com/api/folders/52?per_page=25&sort=created_at&order=desc',
|
||||
'theJWT'
|
||||
)
|
||||
.returns(Promise.resolve({bookmark: '', files: [buttonAndIcon, otherImage]}))
|
||||
|
||||
defaultProps = {
|
||||
context,
|
||||
onImageEmbed: () => {},
|
||||
searchString: '',
|
||||
sortBy: {order: 'desc', sort: 'date_added'},
|
||||
source: apiSource
|
||||
}
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
fetchPageStub.restore()
|
||||
globalFetchStub.restore()
|
||||
})
|
||||
|
||||
const renderComponent = componentProps => {
|
||||
return render(<SavedButtonList {...defaultProps} {...componentProps} />)
|
||||
}
|
||||
|
||||
it('loads and displays svgs', async () => {
|
||||
const {getByAltText} = renderComponent()
|
||||
|
||||
await waitFor(() => expect(getByAltText('button.svg')).toBeInTheDocument())
|
||||
})
|
||||
|
||||
it('ignores non-svg files', async () => {
|
||||
const {queryByAltText} = renderComponent()
|
||||
|
||||
await waitFor(() => queryByAltText('button.svg') != null)
|
||||
|
||||
expect(queryByAltText('screenshot.jpg')).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('rceToFile', () => {
|
||||
const rceFile = {
|
||||
createdAt: '2021-08-12T18:30:53Z',
|
||||
id: '101',
|
||||
name: 'kitten.gif',
|
||||
thumbnailUrl: 'http://example.com/kitten.png',
|
||||
type: 'image/gif',
|
||||
url: 'http://example.com/kitten.gif'
|
||||
}
|
||||
|
||||
it('returns an object with type as content_type', () => {
|
||||
expect(rceToFile(rceFile).content_type).toStrictEqual('image/gif')
|
||||
})
|
||||
|
||||
it('returns an object with createdAt as date', () => {
|
||||
expect(rceToFile(rceFile).date).toStrictEqual('2021-08-12T18:30:53Z')
|
||||
})
|
||||
|
||||
it('returns an object with name as display_name', () => {
|
||||
expect(rceToFile(rceFile).display_name).toStrictEqual('kitten.gif')
|
||||
})
|
||||
|
||||
it('returns an object with name as filename', () => {
|
||||
expect(rceToFile(rceFile).filename).toStrictEqual('kitten.gif')
|
||||
})
|
||||
|
||||
it('returns an object with url as href', () => {
|
||||
expect(rceToFile(rceFile).href).toStrictEqual('http://example.com/kitten.gif')
|
||||
})
|
||||
|
||||
it('returns an object with id as id', () => {
|
||||
expect(rceToFile(rceFile).id).toStrictEqual('101')
|
||||
})
|
||||
|
||||
it('returns an object with thumbnailUrl as thumbnail_url', () => {
|
||||
expect(rceToFile(rceFile).thumbnail_url).toStrictEqual('http://example.com/kitten.png')
|
||||
})
|
||||
})
|
|
@ -16,12 +16,13 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import bridge from '../../../bridge'
|
||||
import formatMessage from '../../../format-message'
|
||||
import {isOKToLink} from '../../contentInsertionUtils'
|
||||
import clickCallback from './clickCallback'
|
||||
|
||||
const CREATE_BUTTON = 'create'
|
||||
const LIST_BUTTON = 'list'
|
||||
const LIST_BUTTON = 'list_buttons_and_icons'
|
||||
|
||||
function getMenuItems() {
|
||||
return [
|
||||
|
@ -52,9 +53,13 @@ function handleOptionSelected(ed, value) {
|
|||
tinymce.create('tinymce.plugins.InstructureButtonsPlugin', {
|
||||
init(ed) {
|
||||
// Register tray control command
|
||||
ed.addCommand('instructureTrayForButtonsPlugin', (ui, type) =>
|
||||
clickCallback(ed, document, type)
|
||||
)
|
||||
ed.addCommand('instructureTrayForButtonsPlugin', (_ui, type) => {
|
||||
if (type === LIST_BUTTON) {
|
||||
bridge.showTrayForPlugin(type, ed.id)
|
||||
} else {
|
||||
clickCallback(ed, document)
|
||||
}
|
||||
})
|
||||
|
||||
// Register menu items
|
||||
ed.ui.registry.addNestedMenuItem('instructure_buttons', {
|
||||
|
|
|
@ -46,6 +46,8 @@ function getTrayLabel(contentType, contentSubtype, contextType) {
|
|||
}
|
||||
|
||||
switch (contentSubtype) {
|
||||
case 'buttons_and_icons':
|
||||
return formatMessage('Buttons and Icons')
|
||||
case 'images':
|
||||
if (contentType === 'course_files') return formatMessage('Course Images')
|
||||
if (contentType === 'group_files') return formatMessage('Group Images')
|
||||
|
@ -64,6 +66,7 @@ function getTrayLabel(contentType, contentSubtype, contextType) {
|
|||
}
|
||||
|
||||
const thePanels = {
|
||||
buttons_and_icons: React.lazy(() => import('../instructure_buttons/components/SavedButtonList')),
|
||||
links: React.lazy(() => import('../instructure_links/components/LinksPanel')),
|
||||
images: React.lazy(() => import('../instructure_image/Images')),
|
||||
documents: React.lazy(() => import('../instructure_documents/components/DocumentsPanel')),
|
||||
|
@ -182,6 +185,14 @@ const FILTER_SETTINGS_BY_PLUGIN = {
|
|||
sortDir: 'desc',
|
||||
searchString: ''
|
||||
},
|
||||
list_buttons_and_icons: {
|
||||
contextType: 'course',
|
||||
contentType: 'course_files',
|
||||
contentSubtype: 'buttons_and_icons',
|
||||
sortValue: 'date_added',
|
||||
sortDir: 'desc',
|
||||
searchString: ''
|
||||
},
|
||||
all: {
|
||||
contextType: 'course',
|
||||
contentType: 'course_files',
|
||||
|
|
|
@ -72,6 +72,7 @@ function renderTypeOptions(contentType, contentSubtype, userContextType) {
|
|||
{formatMessage('Links')}
|
||||
</SimpleSelect.Option>
|
||||
]
|
||||
|
||||
if (userContextType === 'course' && contentType !== 'links' && contentSubtype !== 'all') {
|
||||
options.push(
|
||||
<SimpleSelect.Option
|
||||
|
@ -84,6 +85,7 @@ function renderTypeOptions(contentType, contentSubtype, userContextType) {
|
|||
</SimpleSelect.Option>
|
||||
)
|
||||
}
|
||||
|
||||
if (userContextType === 'group' && contentType !== 'links' && contentSubtype !== 'all') {
|
||||
options.push(
|
||||
<SimpleSelect.Option
|
||||
|
@ -96,16 +98,23 @@ function renderTypeOptions(contentType, contentSubtype, userContextType) {
|
|||
</SimpleSelect.Option>
|
||||
)
|
||||
}
|
||||
options.push(
|
||||
<SimpleSelect.Option
|
||||
key="user_files"
|
||||
id="user_files"
|
||||
value="user_files"
|
||||
renderBeforeLabel={IconFolderLine}
|
||||
>
|
||||
{fileLabelFromContext(contentType === 'links' || contentSubtype === 'all' ? 'files' : 'user')}
|
||||
</SimpleSelect.Option>
|
||||
)
|
||||
|
||||
// Buttons and Icons are only stored in course folders.
|
||||
if (contentSubtype !== 'buttons_and_icons') {
|
||||
options.push(
|
||||
<SimpleSelect.Option
|
||||
key="user_files"
|
||||
id="user_files"
|
||||
value="user_files"
|
||||
renderBeforeLabel={IconFolderLine}
|
||||
>
|
||||
{fileLabelFromContext(
|
||||
contentType === 'links' || contentSubtype === 'all' ? 'files' : 'user'
|
||||
)}
|
||||
</SimpleSelect.Option>
|
||||
)
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
|
@ -222,6 +231,9 @@ export default function Filter(props) {
|
|||
// when flipped to All, the context needs to be user
|
||||
// so we can get media_objects, which are all returned in the user context
|
||||
changed.contentType = 'user_files'
|
||||
} else if (changed.contentSubtype === 'buttons_and_icons') {
|
||||
// Buttons and Icons only belong to Courses.
|
||||
changed.contentType = 'course_files'
|
||||
}
|
||||
onChange(changed)
|
||||
}}
|
||||
|
@ -243,6 +255,14 @@ export default function Filter(props) {
|
|||
{formatMessage('Media')}
|
||||
</SimpleSelect.Option>
|
||||
|
||||
<SimpleSelect.Option
|
||||
id="buttons_and_icons"
|
||||
value="buttons_and_icons"
|
||||
renderBeforeLabel={IconImageLine}
|
||||
>
|
||||
{formatMessage('Buttons and Icons')}
|
||||
</SimpleSelect.Option>
|
||||
|
||||
<SimpleSelect.Option id="all" value="all">
|
||||
{formatMessage('All')}
|
||||
</SimpleSelect.Option>
|
||||
|
|
|
@ -112,6 +112,11 @@ describe('RCE Plugins > CanvasContentTray', () => {
|
|||
await showTrayForPlugin('user_documents')
|
||||
expect(getTrayLabel()).toEqual('User Documents')
|
||||
})
|
||||
|
||||
it('is labeled with "Buttons and Icons" when using the "list_buttons_and_icons" content type', async () => {
|
||||
await showTrayForPlugin('list_buttons_and_icons')
|
||||
expect(getTrayLabel()).toEqual('Buttons and Icons')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Tray Label in group context', () => {
|
||||
|
@ -165,6 +170,13 @@ describe('RCE Plugins > CanvasContentTray', () => {
|
|||
)
|
||||
})
|
||||
|
||||
it('is the images panel for button and icons content types', async () => {
|
||||
await showTrayForPlugin('list_buttons_and_icons')
|
||||
await waitFor(() =>
|
||||
expect(component.getByTestId('instructure_links-ImagesPanel')).toBeInTheDocument()
|
||||
)
|
||||
})
|
||||
|
||||
it('is the media panel for media content types', async () => {
|
||||
await showTrayForPlugin('course_media')
|
||||
await waitFor(() =>
|
||||
|
|
|
@ -230,6 +230,28 @@ describe('RCE Plugins > Filter', () => {
|
|||
selectContentSubtype('Media')
|
||||
expect(currentFilterSettings.sortValue).toEqual('date_added')
|
||||
})
|
||||
|
||||
describe('when "Buttons and Icons" is selected', () => {
|
||||
beforeEach(() => {
|
||||
selectContentSubtype('Buttons and Icons')
|
||||
})
|
||||
|
||||
it('sets the content subtype to "buttons_and_icons"', () => {
|
||||
expect(currentFilterSettings.contentSubtype).toEqual('buttons_and_icons')
|
||||
})
|
||||
|
||||
it('sets the content type to "course_files"', () => {
|
||||
expect(currentFilterSettings.contentType).toEqual('course_files')
|
||||
})
|
||||
|
||||
it('does not render "User Files" content type', () => {
|
||||
expect(component.queryByTitle('User Files')).toBeNull()
|
||||
})
|
||||
|
||||
it('renders the "Course Files" content type', () => {
|
||||
expect(component.getByTitle('Course Files')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('deals with switching to and from Links', () => {
|
||||
|
|
|
@ -34,7 +34,8 @@ export function propsFromState(state) {
|
|||
newPageLinkExpanded,
|
||||
all_files,
|
||||
jwt,
|
||||
host
|
||||
host,
|
||||
source
|
||||
} = state
|
||||
|
||||
const collections = {}
|
||||
|
@ -61,6 +62,7 @@ export function propsFromState(state) {
|
|||
...ui,
|
||||
all_files,
|
||||
jwt,
|
||||
host
|
||||
host,
|
||||
source
|
||||
}
|
||||
}
|
||||
|
|
|
@ -264,6 +264,10 @@ class RceApiSource {
|
|||
if (!bookmark) {
|
||||
const perPageQuery = props.perPage ? `per_page=${props.perPage}` : ''
|
||||
uri = `${props.filesUrl}?${perPageQuery}${getSearchParam(props.searchString)}`
|
||||
|
||||
if (props.sortBy) {
|
||||
uri += `${getSortParams(props.sortBy.sort, props.sortBy.order)}`
|
||||
}
|
||||
}
|
||||
|
||||
return this.fetchPage(uri || bookmark, this.jwt)
|
||||
|
@ -274,11 +278,44 @@ class RceApiSource {
|
|||
return this.apiFetch(uri, headerFor(this.jwt))
|
||||
}
|
||||
|
||||
fetchButtonsAndIconsFolder(props) {
|
||||
const uri = this.uriFor('folders/buttons_and_icons', props)
|
||||
fetchButtonsAndIconsFolder({contextId, contextType}) {
|
||||
const uri = this.uriFor('folders/buttons_and_icons', {
|
||||
contextId,
|
||||
contextType,
|
||||
host: this.host,
|
||||
jwt: this.jwt
|
||||
})
|
||||
return this.fetchPage(uri)
|
||||
}
|
||||
|
||||
fetchButtonsAndIcons(
|
||||
{contextId, contextType},
|
||||
bookmark = null,
|
||||
searchString = null,
|
||||
sortBy,
|
||||
onSuccess
|
||||
) {
|
||||
const onSuccessWithFixedFileData = data => {
|
||||
onSuccess({
|
||||
...data,
|
||||
files: data.files.map(file => fixupFileUrl(contextType, contextId, file))
|
||||
})
|
||||
}
|
||||
|
||||
if (bookmark) {
|
||||
this.fetchFilesForFolder(null, bookmark).then(onSuccessWithFixedFileData)
|
||||
} else {
|
||||
this.fetchButtonsAndIconsFolder({contextId, contextType}).then(({folders}) => {
|
||||
this.fetchFilesForFolder({
|
||||
filesUrl: folders[0].filesUrl,
|
||||
perPage: 25,
|
||||
searchString,
|
||||
sortBy
|
||||
}).then(onSuccessWithFixedFileData)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fetchMediaFolder(props) {
|
||||
let uri
|
||||
if (props.contextType === 'user') {
|
||||
|
|
|
@ -443,8 +443,7 @@ const UNSPLASH_RESULTS = {
|
|||
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',
|
||||
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'
|
||||
},
|
||||
|
@ -458,8 +457,7 @@ const UNSPLASH_RESULTS = {
|
|||
},
|
||||
{
|
||||
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',
|
||||
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'
|
||||
},
|
||||
|
@ -479,8 +477,7 @@ const UNSPLASH_RESULTS = {
|
|||
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',
|
||||
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'
|
||||
},
|
||||
|
@ -494,8 +491,7 @@ const UNSPLASH_RESULTS = {
|
|||
},
|
||||
{
|
||||
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',
|
||||
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'
|
||||
},
|
||||
|
@ -515,8 +511,7 @@ const UNSPLASH_RESULTS = {
|
|||
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',
|
||||
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'
|
||||
},
|
||||
|
@ -530,8 +525,7 @@ const UNSPLASH_RESULTS = {
|
|||
},
|
||||
{
|
||||
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',
|
||||
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'
|
||||
},
|
||||
|
@ -545,8 +539,7 @@ const UNSPLASH_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',
|
||||
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'
|
||||
},
|
||||
|
@ -560,8 +553,7 @@ const UNSPLASH_RESULTS = {
|
|||
},
|
||||
{
|
||||
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',
|
||||
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'
|
||||
},
|
||||
|
@ -575,8 +567,7 @@ const UNSPLASH_RESULTS = {
|
|||
},
|
||||
{
|
||||
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',
|
||||
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'
|
||||
},
|
||||
|
@ -590,8 +581,7 @@ const UNSPLASH_RESULTS = {
|
|||
},
|
||||
{
|
||||
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',
|
||||
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'
|
||||
},
|
||||
|
@ -605,8 +595,7 @@ const UNSPLASH_RESULTS = {
|
|||
},
|
||||
{
|
||||
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',
|
||||
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'
|
||||
},
|
||||
|
@ -620,8 +609,7 @@ const UNSPLASH_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',
|
||||
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'
|
||||
},
|
||||
|
@ -635,8 +623,7 @@ const UNSPLASH_RESULTS = {
|
|||
},
|
||||
{
|
||||
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',
|
||||
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'
|
||||
},
|
||||
|
@ -650,8 +637,7 @@ const UNSPLASH_RESULTS = {
|
|||
},
|
||||
{
|
||||
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',
|
||||
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'
|
||||
},
|
||||
|
@ -749,6 +735,8 @@ export function initializeMedia(_props) {
|
|||
}
|
||||
}
|
||||
|
||||
export function fetchButtonsAndIcons() {}
|
||||
|
||||
export function fetchFolders() {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
|
|
|
@ -411,6 +411,110 @@ describe('sources/api', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('fetchButtonsAndIcons', () => {
|
||||
const props = {contextId: '1', contextType: 'course'}
|
||||
|
||||
beforeEach(() => {
|
||||
const fetchPageResponseBody = {
|
||||
bookmark: 'http://example.com/?p=3',
|
||||
files: [
|
||||
{
|
||||
id: '101',
|
||||
name: 'button.svg',
|
||||
thumbnailUrl: '/files/1/download',
|
||||
type: 'image/svg+xml',
|
||||
url: '/files/1/download/'
|
||||
}
|
||||
]
|
||||
}
|
||||
sinon.stub(apiSource, 'fetchPage').returns(Promise.resolve(fetchPageResponseBody))
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
apiSource.fetchPage.restore()
|
||||
})
|
||||
|
||||
describe('when a bookmark is present', () => {
|
||||
it('fetches with the bookmark', () => {
|
||||
apiSource.fetchButtonsAndIcons(props, 'http://example.com/?p=2', () => {})
|
||||
sinon.assert.calledWith(apiSource.fetchPage, 'http://example.com/?p=2')
|
||||
})
|
||||
|
||||
it('calls the onSuccess arg with the returned bookmark', () => {
|
||||
const onSuccess = ({bookmark}) => {
|
||||
assert.strictEqual(bookmark, fetchPageResponseBody.bookmark)
|
||||
}
|
||||
|
||||
apiSource.fetchButtonsAndIcons(props, 'http://example.com/?p=2', onSuccess)
|
||||
})
|
||||
|
||||
it('calls the onSuccess arg with the returned files', () => {
|
||||
const onSuccess = ({files}) => {
|
||||
assert.deepEqual(files, [
|
||||
{
|
||||
id: '101',
|
||||
name: 'button.svg',
|
||||
thumbnailUrl: '/files/1/download',
|
||||
type: 'image/svg+xml',
|
||||
url: '/courses/1/files/1?wrap=1' // url is normalized to include the context
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
apiSource.fetchButtonsAndIcons(props, 'http://example.com/?p=2', onSuccess)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when a bookmark is not present', () => {
|
||||
const filesUrl = 'http://example.com'
|
||||
const folderResponseBody = {
|
||||
bookmark: 'http://example.com/?p=2',
|
||||
folders: [{filesUrl, id: 24}]
|
||||
}
|
||||
|
||||
let fetchButtonsAndIconsFolderPromise
|
||||
|
||||
beforeEach(() => {
|
||||
fetchButtonsAndIconsFolderPromise = Promise.resolve(folderResponseBody)
|
||||
sinon.stub(apiSource, 'fetchButtonsAndIconsFolder').returns(promise)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
apiSource.fetchButtonsAndIconsFolder.restore()
|
||||
})
|
||||
|
||||
it('fetches the buttons and icons folder, then fetches the files within that folder', async () => {
|
||||
apiSource.fetchButtonsAndIcons(props, null, () => {})
|
||||
await fetchButtonsAndIconsFolderPromise
|
||||
sinon.assert.calledWith(apiSource.fetchPage, `${filesUrl}?per_page=25`)
|
||||
})
|
||||
|
||||
it('calls the onSuccess arg with the returned bookmark', () => {
|
||||
const onSuccess = ({bookmark}) => {
|
||||
assert.strictEqual(bookmark, folderResponseBody.bookmark)
|
||||
}
|
||||
|
||||
apiSource.fetchButtonsAndIcons(props, null, onSuccess)
|
||||
})
|
||||
|
||||
it('calls the onSuccess arg with the returned files', () => {
|
||||
const onSuccess = ({files}) => {
|
||||
assert.deepEqual(files, [
|
||||
{
|
||||
id: '101',
|
||||
name: 'button.svg',
|
||||
thumbnailUrl: '/files/1/download',
|
||||
type: 'image/svg+xml',
|
||||
url: '/courses/1/files/1?wrap=1' // url is normalized to include the context
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
apiSource.fetchButtonsAndIcons(props, null, onSuccess)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('fetchMediaFolder', () => {
|
||||
let files
|
||||
beforeEach(() => {
|
||||
|
|
Loading…
Reference in New Issue