implement delete for conversation messages
fixes VICE-2143 flag=react_inbox Test Plan: - Enable the react inbox FF - Navigate to the inbox - Delete a conversation message in a conversation - It should work Change-Id: Ie2c11d60edf8d4e8f05643b66ce7acb255783b2b Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/276908 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Chawn Neal <chawn.neal@instructure.com> QA-Review: Chawn Neal <chawn.neal@instructure.com> Product-Review: Chawn Neal <chawn.neal@instructure.com>
This commit is contained in:
parent
74bffb22f0
commit
51e5cb10c8
|
@ -26,6 +26,7 @@ export const Conversation = {
|
|||
fragment: gql`
|
||||
fragment Conversation on Conversation {
|
||||
_id
|
||||
id
|
||||
contextId
|
||||
contextType
|
||||
contextName
|
||||
|
@ -47,6 +48,7 @@ export const Conversation = {
|
|||
|
||||
shape: shape({
|
||||
_id: string,
|
||||
id: string,
|
||||
contextId: string,
|
||||
contextType: string,
|
||||
contextName: string,
|
||||
|
@ -61,6 +63,7 @@ export const Conversation = {
|
|||
|
||||
mock: ({
|
||||
_id = '196',
|
||||
id = 'Q29udmVyc2F0aW9uLTE5Ng==',
|
||||
contextId = '195',
|
||||
contextType = 'Course',
|
||||
contextName = 'XavierSchool',
|
||||
|
@ -118,6 +121,7 @@ export const Conversation = {
|
|||
}
|
||||
} = {}) => ({
|
||||
_id,
|
||||
id,
|
||||
contextId,
|
||||
contextType,
|
||||
contextName,
|
||||
|
|
|
@ -136,3 +136,14 @@ export const ADD_CONVERSATION_MESSAGE = gql`
|
|||
${Error.fragment}
|
||||
${ConversationMessage.fragment}
|
||||
`
|
||||
|
||||
export const DELETE_CONVERSATION_MESSAGES = gql`
|
||||
mutation DeleteConversationMessages($ids: [ID!]!) {
|
||||
deleteConversationMessages(input: {ids: $ids}) {
|
||||
conversationMessageIds
|
||||
errors {
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
|
@ -66,6 +66,7 @@ export const handlers = [
|
|||
}),
|
||||
conversation: Conversation.mock({
|
||||
_id: '195',
|
||||
id: 'Q29udmVyc2F0aW9uLTE5NQ==',
|
||||
subject: 'h1'
|
||||
})
|
||||
}
|
||||
|
@ -99,6 +100,7 @@ export const handlers = [
|
|||
...ConversationParticipant.mock({_id: '123', id: 'Q29udmVyc2F0aW9uUGFydGljaXBhbnQtMTA='}),
|
||||
conversation: Conversation.mock({
|
||||
_id: '10',
|
||||
id: 'Q29udmVyc2F0aW9uLTEw',
|
||||
subject: 'This is a course scoped conversation'
|
||||
})
|
||||
}
|
||||
|
@ -112,7 +114,11 @@ export const handlers = [
|
|||
{_id: '256', id: 'Q29udmVyc2F0aW9uUGFydGljaXBhbnQtMjU2', workflowState: 'unread'},
|
||||
{_id: '257', id: 'Q29udmVyc2F0aW9uUGFydGljaXBhbnQtMjU4', workflowState: 'unread'}
|
||||
),
|
||||
conversation: Conversation.mock({_id: '197', subject: 'This is an inbox conversation'})
|
||||
conversation: Conversation.mock({
|
||||
_id: '197',
|
||||
id: 'Q29udmVyc2F0aW9uLTE5Nw==',
|
||||
subject: 'This is an inbox conversation'
|
||||
})
|
||||
}
|
||||
]
|
||||
data.legacyNode.conversationsConnection.nodes[0].conversation.conversationMessagesConnection.nodes =
|
||||
|
|
|
@ -58,7 +58,9 @@ export const MessageDetailActions = ({...props}) => {
|
|||
{I18n.t('Reply All')}
|
||||
</Menu.Item>
|
||||
<Menu.Item value="forward">{I18n.t('Forward')}</Menu.Item>
|
||||
<Menu.Item value="delete">{I18n.t('Delete')}</Menu.Item>
|
||||
<Menu.Item value="delete" onSelect={props.onDelete}>
|
||||
{I18n.t('Delete')}
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
</>
|
||||
)
|
||||
|
@ -66,5 +68,6 @@ export const MessageDetailActions = ({...props}) => {
|
|||
|
||||
MessageDetailActions.propTypes = {
|
||||
onReply: PropTypes.func,
|
||||
onReplyAll: PropTypes.func
|
||||
onReplyAll: PropTypes.func,
|
||||
onDelete: PropTypes.func
|
||||
}
|
||||
|
|
|
@ -25,7 +25,8 @@ export default {
|
|||
component: MessageDetailActions,
|
||||
argTypes: {
|
||||
onReply: {action: 'reply'},
|
||||
onReplyAll: {action: 'replyAll'}
|
||||
onReplyAll: {action: 'replyAll'},
|
||||
onDelete: {action: 'delete'}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,8 @@ describe('MessageDetailItem', () => {
|
|||
it('sends the selected option to the provided callback function', () => {
|
||||
const props = {
|
||||
onReply: jest.fn(),
|
||||
onReplyAll: jest.fn()
|
||||
onReplyAll: jest.fn(),
|
||||
onDelete: jest.fn()
|
||||
}
|
||||
const {getByRole, getByText} = render(<MessageDetailActions {...props} />)
|
||||
|
||||
|
@ -40,5 +41,9 @@ describe('MessageDetailItem', () => {
|
|||
fireEvent.click(moreOptionsButton)
|
||||
fireEvent.click(getByText('Reply All'))
|
||||
expect(props.onReplyAll).toHaveBeenCalled()
|
||||
|
||||
fireEvent.click(moreOptionsButton)
|
||||
fireEvent.click(getByText('Delete'))
|
||||
expect(props.onDelete).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
|
|
@ -64,7 +64,11 @@ export const MessageDetailItem = ({...props}) => {
|
|||
<View as="div" margin="none none x-small">
|
||||
<Text weight="light">{createdAt}</Text>
|
||||
</View>
|
||||
<MessageDetailActions onReply={props.onReply} onReplyAll={props.onReplyAll} />
|
||||
<MessageDetailActions
|
||||
onReply={props.onReply}
|
||||
onReplyAll={props.onReplyAll}
|
||||
onDelete={props.onDelete}
|
||||
/>
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
<Text>{props.conversationMessage.body}</Text>
|
||||
|
@ -93,7 +97,8 @@ MessageDetailItem.propTypes = {
|
|||
conversationMessage: PropTypes.object,
|
||||
contextName: PropTypes.string,
|
||||
onReply: PropTypes.func,
|
||||
onReplyAll: PropTypes.func
|
||||
onReplyAll: PropTypes.func,
|
||||
onDelete: PropTypes.func
|
||||
}
|
||||
|
||||
MessageDetailItem.defaultProps = {
|
||||
|
|
|
@ -25,7 +25,8 @@ export default {
|
|||
component: MessageDetailItem,
|
||||
argTypes: {
|
||||
onReply: {action: 'reply'},
|
||||
onReplyAll: {action: 'replyAll'}
|
||||
onReplyAll: {action: 'replyAll'},
|
||||
onDelete: {action: 'delete'}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,7 +79,8 @@ describe('MessageDetailItem', () => {
|
|||
},
|
||||
contextName: 'Fake Course 1',
|
||||
onReply: jest.fn(),
|
||||
onReplyAll: jest.fn()
|
||||
onReplyAll: jest.fn(),
|
||||
onDelete: jest.fn()
|
||||
}
|
||||
|
||||
const {getByTestId, getByText} = render(<MessageDetailItem {...props} />)
|
||||
|
@ -92,5 +93,9 @@ describe('MessageDetailItem', () => {
|
|||
fireEvent.click(moreOptionsButton)
|
||||
fireEvent.click(getByText('Reply All'))
|
||||
expect(props.onReplyAll).toHaveBeenCalled()
|
||||
|
||||
fireEvent.click(moreOptionsButton)
|
||||
fireEvent.click(getByText('Delete'))
|
||||
expect(props.onDelete).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
|
|
@ -16,15 +16,54 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {AlertManagerContext} from '@canvas/alerts/react/AlertManager'
|
||||
import {Conversation} from '../../../graphql/Conversation'
|
||||
import {DELETE_CONVERSATION_MESSAGES} from '../../../graphql/Mutations'
|
||||
import I18n from 'i18n!conversations_2'
|
||||
import {MessageDetailHeader} from '../../components/MessageDetailHeader/MessageDetailHeader'
|
||||
import {MessageDetailItem} from '../../components/MessageDetailItem/MessageDetailItem'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
|
||||
import React, {useContext} from 'react'
|
||||
import {useMutation} from 'react-apollo'
|
||||
import {View} from '@instructure/ui-view'
|
||||
|
||||
export const MessageDetailContainer = props => {
|
||||
const {setOnFailure, setOnSuccess} = useContext(AlertManagerContext)
|
||||
|
||||
const removeConversationMessagesFromCache = (cache, result) => {
|
||||
const data = JSON.parse(
|
||||
JSON.stringify(
|
||||
cache.readFragment({
|
||||
id: props.conversation.id,
|
||||
fragment: Conversation.fragment,
|
||||
fragmentName: 'Conversation'
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||
data.conversationMessagesConnection.nodes = data.conversationMessagesConnection.nodes.filter(
|
||||
message =>
|
||||
!result.data.deleteConversationMessages.conversationMessageIds.includes(message._id)
|
||||
)
|
||||
|
||||
cache.writeFragment({
|
||||
id: props.conversation.id,
|
||||
fragment: Conversation.fragment,
|
||||
fragmentName: 'Conversation',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
const [deleteConversationMessages] = useMutation(DELETE_CONVERSATION_MESSAGES, {
|
||||
update: removeConversationMessagesFromCache,
|
||||
onCompleted() {
|
||||
setOnSuccess(I18n.t('Successfully deleted the conversation message'))
|
||||
},
|
||||
onError() {
|
||||
setOnFailure(I18n.t('There was an unexpected error deleting the conversation message'))
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
<MessageDetailHeader
|
||||
|
@ -39,6 +78,7 @@ export const MessageDetailContainer = props => {
|
|||
context={props.conversation.contextName}
|
||||
onReply={() => props.onReply(message)}
|
||||
onReplyAll={() => props.onReplyAll(message)}
|
||||
onDelete={() => deleteConversationMessages({variables: {ids: [message._id]}})}
|
||||
/>
|
||||
</View>
|
||||
))}
|
||||
|
|
Loading…
Reference in New Issue