diff --git a/app/jsx/content_shares/CourseImportPanel.js b/app/jsx/content_shares/CourseImportPanel.js
index 09e5bb96d52..bc98a539727 100644
--- a/app/jsx/content_shares/CourseImportPanel.js
+++ b/app/jsx/content_shares/CourseImportPanel.js
@@ -46,7 +46,7 @@ export default function CourseImportPanel({contentShare, onClose, onImport}) {
migration_type: 'canvas_cartridge_importer',
settings: {
content_export_id: contentShare.content_export.id,
- insert_into_module_id: selectedModule?.id,
+ insert_into_module_id: selectedModule?.id || null,
insert_into_module_type: contentShare.content_type,
insert_into_module_position: selectedPosition
}
@@ -56,6 +56,11 @@ export default function CourseImportPanel({contentShare, onClose, onImport}) {
onImport(contentShare)
}
+ function handleSelectedCourse(course) {
+ setSelectedModule(null)
+ setSelectedCourse(course)
+ }
+
return (
<>
diff --git a/app/jsx/content_shares/__tests__/CourseImportPanel.test.js b/app/jsx/content_shares/__tests__/CourseImportPanel.test.js
index c2a13e5945f..8cd2862efca 100644
--- a/app/jsx/content_shares/__tests__/CourseImportPanel.test.js
+++ b/app/jsx/content_shares/__tests__/CourseImportPanel.test.js
@@ -20,7 +20,9 @@ import React from 'react'
import {render, fireEvent, act} from '@testing-library/react'
import fetchMock from 'fetch-mock'
import useManagedCourseSearchApi from 'jsx/shared/effects/useManagedCourseSearchApi'
-import useModuleCourseSearchApi from 'jsx/shared/effects/useModuleCourseSearchApi'
+import useModuleCourseSearchApi, {
+ useCourseModuleItemApi
+} from 'jsx/shared/effects/useModuleCourseSearchApi'
import CourseImportPanel from '../CourseImportPanel'
import {mockShare} from 'jsx/content_shares/__tests__/test-utils'
@@ -43,7 +45,10 @@ describe('CourseImportPanel', () => {
beforeEach(() => {
useManagedCourseSearchApi.mockImplementationOnce(({success}) => {
- success([{id: 'abc', name: 'abc'}, {id: 'cde', name: 'cde'}])
+ success([
+ {id: 'abc', name: 'abc'},
+ {id: 'cde', name: 'cde'}
+ ])
})
})
@@ -93,7 +98,10 @@ describe('CourseImportPanel', () => {
workflow_state: 'running'
})
useModuleCourseSearchApi.mockImplementationOnce(({success}) => {
- success([{id: '1', name: 'Module 1'}, {id: '2', name: 'Module 2'}])
+ success([
+ {id: '1', name: 'Module 1'},
+ {id: '2', name: 'Module 2'}
+ ])
})
const {getByText, getByLabelText, queryByText} = render(
@@ -121,6 +129,34 @@ describe('CourseImportPanel', () => {
expect(onImport.mock.calls[0][0]).toBe(share)
})
+ it('deletes the module and removes the position selector when a new course is selected', () => {
+ const share = mockShare()
+ useModuleCourseSearchApi.mockImplementationOnce(({success}) => {
+ success([
+ {id: '1', name: 'Module 1'},
+ {id: '2', name: 'Module 2'}
+ ])
+ })
+ const {getByText, getByLabelText, queryByText} = render(
+
+ )
+ const courseSelector = getByText(/select a course/i)
+ fireEvent.click(courseSelector)
+ fireEvent.click(getByText('abc'))
+ fireEvent.click(getByText(/select a module/i))
+ fireEvent.click(getByText(/Module 1/))
+ expect(getByText(/Position/)).toBeInTheDocument()
+ useManagedCourseSearchApi.mockImplementationOnce(({success}) => {
+ success([{id: 'ghi', name: 'foo'}])
+ })
+ useCourseModuleItemApi.mockClear()
+ const input = getByLabelText(/select a course/i)
+ fireEvent.change(input, {target: {value: 'fo'}})
+ fireEvent.click(getByText('foo'))
+ expect(queryByText(/Position/)).not.toBeInTheDocument()
+ expect(useCourseModuleItemApi).not.toHaveBeenCalled()
+ })
+
describe('errors', () => {
beforeEach(() => {
jest.spyOn(console, 'error').mockImplementation()
diff --git a/app/jsx/shared/components/ConfirmActionButtonBar.js b/app/jsx/shared/components/ConfirmActionButtonBar.js
index 55793b5a348..df074affe51 100644
--- a/app/jsx/shared/components/ConfirmActionButtonBar.js
+++ b/app/jsx/shared/components/ConfirmActionButtonBar.js
@@ -19,7 +19,7 @@
import React from 'react'
import {bool, string, func} from 'prop-types'
import {Button} from '@instructure/ui-buttons'
-import {Flex} from '@instructure/ui-layout'
+import {Flex} from '@instructure/ui-flex'
ConfirmActionButtonBar.propTypes = {
// only buttons with labels will be displayed
diff --git a/app/jsx/shared/direct_share/CourseAndModulePicker.js b/app/jsx/shared/direct_share/CourseAndModulePicker.js
index 4b1043796b6..95750388f37 100644
--- a/app/jsx/shared/direct_share/CourseAndModulePicker.js
+++ b/app/jsx/shared/direct_share/CourseAndModulePicker.js
@@ -52,25 +52,25 @@ export default function CourseAndModulePicker({
itemSearchFunction={useManagedCourseSearchApi}
/>
-
- {selectedCourseId && (
+ {selectedCourseId && (
+
- )}
-
-
- {selectedCourseId && selectedModuleId && (
+
+ )}
+ {selectedCourseId && selectedModuleId && (
+
- )}
-
+
+ )}
>
)
diff --git a/app/jsx/shared/direct_share/DirectShareCoursePanel.js b/app/jsx/shared/direct_share/DirectShareCoursePanel.js
index 7fa3ca63be8..04bd30b5fc8 100644
--- a/app/jsx/shared/direct_share/DirectShareCoursePanel.js
+++ b/app/jsx/shared/direct_share/DirectShareCoursePanel.js
@@ -52,7 +52,7 @@ export default function DirectShareCoursePanel({sourceCourseId, contentSelection
select: contentSelection,
settings: {
source_course_id: sourceCourseId,
- insert_into_module_id: selectedModule?.id,
+ insert_into_module_id: selectedModule?.id || null,
insert_into_module_type: contentSelection ? Object.keys(contentSelection)[0] : null,
insert_into_module_position: selectedPosition
}
@@ -61,6 +61,11 @@ export default function DirectShareCoursePanel({sourceCourseId, contentSelection
)
}
+ function handleSelectedCourse(course) {
+ setSelectedModule(null)
+ setSelectedCourse(course)
+ }
+
return (
<>
diff --git a/app/jsx/shared/direct_share/__tests__/CourseAndModulePicker.test.js b/app/jsx/shared/direct_share/__tests__/CourseAndModulePicker.test.js
index e1de49bba39..debdc8f748e 100644
--- a/app/jsx/shared/direct_share/__tests__/CourseAndModulePicker.test.js
+++ b/app/jsx/shared/direct_share/__tests__/CourseAndModulePicker.test.js
@@ -17,9 +17,11 @@
*/
import React from 'react'
-import {render} from '@testing-library/react'
+import {render, fireEvent} from '@testing-library/react'
import useManagedCourseSearchApi from 'jsx/shared/effects/useManagedCourseSearchApi'
-import useModuleCourseSearchApi from 'jsx/shared/effects/useModuleCourseSearchApi'
+import useModuleCourseSearchApi, {
+ useCourseModuleItemApi
+} from 'jsx/shared/effects/useModuleCourseSearchApi'
import CourseAndModulePicker from '../CourseAndModulePicker'
jest.mock('jsx/shared/effects/useManagedCourseSearchApi')
@@ -39,15 +41,73 @@ describe('CourseAndModulePicker', () => {
if (ariaLive) ariaLive.remove()
})
- it('enables the module selector when a course is selected', () => {
+ it('shows course selector by default', () => {
useManagedCourseSearchApi.mockImplementationOnce(({success}) => {
- success([{id: 'abc', name: 'abc'}, {id: 'cde', name: 'cde'}])
+ success([
+ {id: 'abc', name: 'abc'},
+ {id: 'cde', name: 'cde'}
+ ])
+ })
+ const setCourse = jest.fn()
+ const {getByText} = render()
+ const selector = getByText(/select a course/i)
+ fireEvent.click(selector)
+ fireEvent.click(getByText('abc'))
+ expect(setCourse).toHaveBeenLastCalledWith({id: 'abc', name: 'abc'})
+ })
+
+ it('shows the course and module selector when a course is given', () => {
+ useManagedCourseSearchApi.mockImplementationOnce(({success}) => {
+ success([
+ {id: 'abc', name: 'abc'},
+ {id: 'cde', name: 'cde'}
+ ])
})
useModuleCourseSearchApi.mockImplementationOnce(({success}) => {
- success([{id: '1', name: 'Module 1'}, {id: '2', name: 'Module 2'}])
+ success([
+ {id: '1', name: 'Module 1'},
+ {id: '2', name: 'Module 2'}
+ ])
})
- const {getByText} = render()
- expect(getByText(/select a course/i)).toBeInTheDocument()
- expect(getByText(/select a module/i)).toBeInTheDocument()
+ const setModule = jest.fn()
+ const {getByText} = render(
+
+ )
+ const selector = getByText(/select a module/i)
+ fireEvent.click(selector)
+ fireEvent.click(getByText('Module 1'))
+ expect(setModule).toHaveBeenLastCalledWith({id: '1', name: 'Module 1'})
+ })
+
+ it('shows the position selector when a module is given', () => {
+ useManagedCourseSearchApi.mockImplementationOnce(({success}) => {
+ success([
+ {id: 'abc', name: 'abc'},
+ {id: 'cde', name: 'cde'}
+ ])
+ })
+ useModuleCourseSearchApi.mockImplementationOnce(({success}) => {
+ success([
+ {id: '1', name: 'Module 1'},
+ {id: '2', name: 'Module 2'}
+ ])
+ })
+ useCourseModuleItemApi.mockImplementationOnce(({success}) => {
+ success([
+ {id: 'a', title: 'Item 1', position: '5'},
+ {id: 'b', title: 'Item 2', position: '6'}
+ ])
+ })
+ const setPosition = jest.fn()
+ const {getByTestId} = render(
+
+ )
+ const selector = getByTestId('select-position')
+ fireEvent.change(selector, {target: {value: 'top'}})
+ expect(setPosition).toHaveBeenLastCalledWith(1)
})
})
diff --git a/app/jsx/shared/direct_share/__tests__/DirectShareCoursePanel.test.js b/app/jsx/shared/direct_share/__tests__/DirectShareCoursePanel.test.js
index d4b303dfdf8..f0d60a55a02 100644
--- a/app/jsx/shared/direct_share/__tests__/DirectShareCoursePanel.test.js
+++ b/app/jsx/shared/direct_share/__tests__/DirectShareCoursePanel.test.js
@@ -20,9 +20,13 @@ import React from 'react'
import {render, fireEvent, act} from '@testing-library/react'
import fetchMock from 'fetch-mock'
import useManagedCourseSearchApi from 'jsx/shared/effects/useManagedCourseSearchApi'
+import useModuleCourseSearchApi, {
+ useCourseModuleItemApi
+} from 'jsx/shared/effects/useModuleCourseSearchApi'
import DirectShareCoursePanel from '../DirectShareCoursePanel'
jest.mock('jsx/shared/effects/useManagedCourseSearchApi')
+jest.mock('jsx/shared/effects/useModuleCourseSearchApi')
describe('DirectShareCoursePanel', () => {
let ariaLive
@@ -40,7 +44,10 @@ describe('DirectShareCoursePanel', () => {
beforeEach(() => {
useManagedCourseSearchApi.mockImplementationOnce(({success}) => {
- success([{id: 'abc', name: 'abc'}, {id: 'cde', name: 'cde'}])
+ success([
+ {id: 'abc', name: 'abc'},
+ {id: 'cde', name: 'cde'}
+ ])
})
})
@@ -121,6 +128,36 @@ describe('DirectShareCoursePanel', () => {
expect(getByText('Close')).toBeInTheDocument()
})
+ it('deletes the module and removes the position selector when a new course is selected', () => {
+ useModuleCourseSearchApi.mockImplementationOnce(({success}) => {
+ success([
+ {id: '1', name: 'Module 1'},
+ {id: '2', name: 'Module 2'}
+ ])
+ })
+ const {getByText, getByLabelText, queryByText} = render(
+
+ )
+ const courseSelector = getByText(/select a course/i)
+ fireEvent.click(courseSelector)
+ fireEvent.click(getByText('abc'))
+ fireEvent.click(getByText(/select a module/i))
+ fireEvent.click(getByText(/Module 1/))
+ expect(getByText(/Position/)).toBeInTheDocument()
+ useManagedCourseSearchApi.mockImplementationOnce(({success}) => {
+ success([{id: 'ghi', name: 'foo'}])
+ })
+ useCourseModuleItemApi.mockClear()
+ const input = getByLabelText(/select a course/i)
+ fireEvent.change(input, {target: {value: 'fo'}})
+ fireEvent.click(getByText('foo'))
+ expect(queryByText(/Position/)).not.toBeInTheDocument()
+ expect(useCourseModuleItemApi).not.toHaveBeenCalled()
+ })
+
describe('errors', () => {
beforeEach(() => {
jest.spyOn(console, 'error').mockImplementation()
diff --git a/app/jsx/shared/helpers/SelectPosition.js b/app/jsx/shared/helpers/SelectPosition.js
index f43599e1bb2..a0f8ee451d9 100644
--- a/app/jsx/shared/helpers/SelectPosition.js
+++ b/app/jsx/shared/helpers/SelectPosition.js
@@ -20,10 +20,10 @@ import React from 'react'
import {string, func, bool, arrayOf, node, shape} from 'prop-types'
import I18n from 'i18n!selectPosition'
import ConnectorIcon from '../../move_item/ConnectorIcon'
-import {Text} from '@instructure/ui-elements'
+import {Text} from '@instructure/ui-text'
import {FormField} from '@instructure/ui-form-field'
import {View} from '@instructure/ui-layout'
-import {ScreenReaderContent} from '@instructure/ui-a11y'
+import {ScreenReaderContent} from '@instructure/ui-a11y-content'
import {positions} from '../../move_item/positions'
import {itemShape} from '../../move_item/propTypes'
diff --git a/package.json b/package.json
index 95a58664758..e0dc32f5298 100644
--- a/package.json
+++ b/package.json
@@ -52,6 +52,7 @@
"@instructure/ui-svg-images": "6",
"@instructure/ui-table": "6",
"@instructure/ui-tabs": "6",
+ "@instructure/ui-text": "6",
"@instructure/ui-text-input": "6",
"@instructure/ui-themeable": "6",
"@instructure/ui-themes": "6",
diff --git a/yarn.lock b/yarn.lock
index bd83bf2fd43..3fc1084cf12 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2331,6 +2331,18 @@
classnames "^2"
prop-types "^15"
+"@instructure/ui-text@6":
+ version "6.15.0"
+ resolved "https://registry.yarnpkg.com/@instructure/ui-text/-/ui-text-6.15.0.tgz#0bceef3fb9a2b5640b54d5f00664a37cee4ce4ba"
+ integrity sha512-KXF73rRC/RkIcryWnHGNnQJi3JcGcGWjJLm0kaDljXCQBS25ypvURg9OCiSYhvyInFB7fLQFP1anAAY2UyPISQ==
+ dependencies:
+ "@babel/runtime" "^7.5.0"
+ "@instructure/console" "^6.15.0"
+ "@instructure/ui-react-utils" "^6.15.0"
+ "@instructure/ui-themeable" "^6.15.0"
+ classnames "^2"
+ prop-types "^15"
+
"@instructure/ui-themeable@6", "@instructure/ui-themeable@^6.15.0", "@instructure/ui-themeable@^6.9.0":
version "6.15.0"
resolved "https://registry.yarnpkg.com/@instructure/ui-themeable/-/ui-themeable-6.15.0.tgz#8ef3f08020731385d9df5d0213c10692e3a1cbd3"