don't attempt to import incomplete content shares
test plan: - create a content share - immediately view the share as the receiver* - it should show as "Pending" and should not have an Import option - wait a minute and refresh the page - it should show a received time and be importable *if you have trouble being fast enough, stop jobs, create the share, visit the page, then start jobs flag = direct_share fixes LS-1353 Change-Id: I6bebdb3f80deb796f3c3c46310f05edf84bd3147 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/245644 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> QA-Review: Robin Kuss <rkuss@instructure.com> Reviewed-by: Ed Schiebel <eschiebel@instructure.com> Product-Review: Jeremy Stanley <jeremy@instructure.com>
This commit is contained in:
parent
307e6bbaf8
commit
b12ab50144
|
@ -49,6 +49,24 @@ ReceivedTable.propTypes = {
|
|||
|
||||
export default function ReceivedTable({shares, onPreview, onImport, onRemove, onUpdate}) {
|
||||
function renderActionMenu(share) {
|
||||
const items = []
|
||||
if (share.content_export?.workflow_state === 'exported') {
|
||||
items.push(
|
||||
<Menu.Item key="prv" data-testid="preview-menu-action" onSelect={() => onPreview(share)}>
|
||||
<IconEyeLine /> <View margin="0 0 0 x-small">{I18n.t('Preview')}</View>
|
||||
</Menu.Item>
|
||||
)
|
||||
items.push(
|
||||
<Menu.Item key="imp" data-testid="import-menu-action" onSelect={() => onImport(share)}>
|
||||
<IconImportLine /> <View margin="0 0 0 x-small">{I18n.t('Import')}</View>
|
||||
</Menu.Item>
|
||||
)
|
||||
}
|
||||
items.push(
|
||||
<Menu.Item key="rmv" data-testid="remove-menu-action" onSelect={() => onRemove(share)}>
|
||||
<IconTrashLine /> <View margin="0 0 0 x-small">{I18n.t('Remove')}</View>
|
||||
</Menu.Item>
|
||||
)
|
||||
return (
|
||||
<Menu
|
||||
data-testid="action-menu"
|
||||
|
@ -60,15 +78,7 @@ export default function ReceivedTable({shares, onPreview, onImport, onRemove, on
|
|||
</Button>
|
||||
}
|
||||
>
|
||||
<Menu.Item data-testid="preview-menu-action" onSelect={() => onPreview(share)}>
|
||||
<IconEyeLine /> <View margin="0 0 0 x-small">{I18n.t('Preview')}</View>
|
||||
</Menu.Item>
|
||||
<Menu.Item data-testid="import-menu-action" onSelect={() => onImport(share)}>
|
||||
<IconImportLine /> <View margin="0 0 0 x-small">{I18n.t('Import')}</View>
|
||||
</Menu.Item>
|
||||
<Menu.Item data-testid="remove-menu-action" onSelect={() => onRemove(share)}>
|
||||
<IconTrashLine /> <View margin="0 0 0 x-small">{I18n.t('Remove')}</View>
|
||||
</Menu.Item>
|
||||
{items}
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
|
@ -137,6 +147,28 @@ export default function ReceivedTable({shares, onPreview, onImport, onRemove, on
|
|||
}
|
||||
}
|
||||
|
||||
function renderReceivedColumn(content_export) {
|
||||
if (content_export && content_export.workflow_state === 'exported') {
|
||||
return <FriendlyDatetime dateTime={content_export.created_at} />
|
||||
} else if (
|
||||
!content_export ||
|
||||
content_export.workflow_state === 'failed' ||
|
||||
content_export.workflow_state === 'deleted'
|
||||
) {
|
||||
return (
|
||||
<Text color="danger">
|
||||
<em>{I18n.t('Failed')}</em>
|
||||
</Text>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Text color="secondary">
|
||||
<em>{I18n.t('Pending')}</em>
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function renderRow(share) {
|
||||
return (
|
||||
<Table.Row key={share.id}>
|
||||
|
@ -155,9 +187,7 @@ export default function ReceivedTable({shares, onPreview, onImport, onRemove, on
|
|||
/>{' '}
|
||||
{share.sender.display_name}
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<FriendlyDatetime dateTime={share.created_at} />
|
||||
</Table.Cell>
|
||||
<Table.Cell>{renderReceivedColumn(share.content_export)}</Table.Cell>
|
||||
<Table.Cell>{renderActionMenu(share)}</Table.Cell>
|
||||
</Table.Row>
|
||||
)
|
||||
|
|
|
@ -20,6 +20,7 @@ import React from 'react'
|
|||
import {fireEvent, render} from '@testing-library/react'
|
||||
import ReceivedTable from 'jsx/content_shares/ReceivedTable'
|
||||
import {
|
||||
mockShare,
|
||||
assignmentShare,
|
||||
readDiscussionShare,
|
||||
unreadDiscussionShare
|
||||
|
@ -123,4 +124,26 @@ describe('content shares table', () => {
|
|||
fireEvent.click(getByText('Remove'))
|
||||
expect(onRemove).toHaveBeenCalledWith(assignmentShare)
|
||||
})
|
||||
|
||||
it('handles a missing content_export', () => {
|
||||
const brokenShare = mockShare({content_export: null})
|
||||
const {getByText, queryByText, queryByTestId} = render(<ReceivedTable shares={[brokenShare]} />)
|
||||
fireEvent.click(getByText(/manage options/i))
|
||||
expect(queryByText('Remove')).toBeInTheDocument()
|
||||
expect(queryByText('Failed')).toBeInTheDocument()
|
||||
expect(queryByTestId('import-menu-action')).not.toBeInTheDocument()
|
||||
expect(queryByTestId('preview-menu-action')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('handles an incomplete content_export', () => {
|
||||
const pendingShare = mockShare({content_export: {id: 4, workflow_state: 'exporting'}})
|
||||
const {getByText, queryByText, queryByTestId} = render(
|
||||
<ReceivedTable shares={[pendingShare]} />
|
||||
)
|
||||
fireEvent.click(getByText(/manage options/i))
|
||||
expect(queryByText('Remove')).toBeInTheDocument()
|
||||
expect(queryByText('Pending')).toBeInTheDocument()
|
||||
expect(queryByTestId('import-menu-action')).not.toBeInTheDocument()
|
||||
expect(queryByTestId('preview-menu-action')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
|
|
@ -31,8 +31,11 @@ export function mockShare(overrides = {}) {
|
|||
read_state: 'read',
|
||||
content_export: {
|
||||
id: '3',
|
||||
workflow_state: 'exported',
|
||||
created_at: '2019-07-04T12:00:00Z',
|
||||
attachment: {
|
||||
id: '4',
|
||||
created_at: '2019-07-04T12:00:00Z',
|
||||
url: 'https://attachment.url'
|
||||
}
|
||||
},
|
||||
|
|
|
@ -37,16 +37,17 @@ describe "direct share page" do
|
|||
@assignment_1 = @course_1.assignments.create!(:title => 'Assignment First', :points_possible => 10)
|
||||
assignment_model(course: @course_1, name: 'assignment to share')
|
||||
@course_1.root_account.enable_feature!(:direct_share)
|
||||
end
|
||||
|
||||
before :each do
|
||||
@export_1 = @course_1.content_exports.create!(settings: {"selected_content" => {"assignments" => {CC::CCHelper.create_key(@assignment_1) => '1'}}})
|
||||
@export_2 = @course_1.content_exports.create!(settings: {"selected_content" => {"assignments" => {CC::CCHelper.create_key(@assignment_1) => '1'}}})
|
||||
@export_3 = @course_1.content_exports.create!(settings: {"selected_content" => {"assignments" => {CC::CCHelper.create_key(@assignment_1) => '1'}}})
|
||||
@export_1 = @course_1.content_exports.create!(workflow_state: 'exported', settings: {"selected_content" => {"assignments" => {CC::CCHelper.create_key(@assignment_1) => '1'}}})
|
||||
@export_2 = @course_1.content_exports.create!(workflow_state: 'exported', settings: {"selected_content" => {"assignments" => {CC::CCHelper.create_key(@assignment_1) => '1'}}})
|
||||
@export_3 = @course_1.content_exports.create!(workflow_state: 'exported', settings: {"selected_content" => {"assignments" => {CC::CCHelper.create_key(@assignment_1) => '1'}}})
|
||||
@sent_share = @teacher_1.sent_content_shares.create! name: 'a-unread share1', content_export: @export_1, read_state: 'unread'
|
||||
@unread_share1 = @teacher_2.received_content_shares.create! name: 'a-unread share1', content_export: @export_1, sender: @teacher_1, read_state: 'unread'
|
||||
@unread_share2 = @teacher_2.received_content_shares.create! name: 'b-unread share2', content_export: @export_2, sender: @teacher_1, read_state: 'unread'
|
||||
@read_share = @teacher_2.received_content_shares.create! name: 'c-read share', content_export: @export_3, sender: @teacher_1, read_state: 'read'
|
||||
end
|
||||
|
||||
before :each do
|
||||
user_session @teacher_2
|
||||
visit_content_share_page
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue