Fixing redo on card contents (#2831)

* Fixing redo on card contents

* Fixing tests
This commit is contained in:
Jesús Espino 2022-04-25 18:08:46 +02:00 committed by GitHub
parent 3e6383b475
commit 340fcf20f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 60 additions and 29 deletions

View file

@ -67,7 +67,7 @@ describe('components/addContentMenuItem', () => {
expect(container).toMatchSnapshot()
const buttonElement = screen.getByRole('button', {name: 'text'})
userEvent.click(buttonElement)
await waitFor(() => expect(mockedMutator.performAsUndoGroup).toBeCalled())
await waitFor(() => expect(mockedMutator.insertBlock).toBeCalled())
})
test('return a checkbox menu item', async () => {
@ -83,7 +83,7 @@ describe('components/addContentMenuItem', () => {
expect(container).toMatchSnapshot()
const buttonElement = screen.getByRole('button', {name: 'checkbox'})
userEvent.click(buttonElement)
await waitFor(() => expect(mockedMutator.performAsUndoGroup).toBeCalled())
await waitFor(() => expect(mockedMutator.insertBlock).toBeCalled())
})
test('return a divider menu item', async () => {
@ -99,7 +99,7 @@ describe('components/addContentMenuItem', () => {
expect(container).toMatchSnapshot()
const buttonElement = screen.getByRole('button', {name: 'divider'})
userEvent.click(buttonElement)
await waitFor(() => expect(mockedMutator.performAsUndoGroup).toBeCalled())
await waitFor(() => expect(mockedMutator.insertBlock).toBeCalled())
})
test('return an error and empty element from unknown type', () => {

View file

@ -6,7 +6,9 @@ import {useIntl} from 'react-intl'
import {BlockTypes} from '../blocks/block'
import {Card} from '../blocks/card'
import {Block} from '../blocks/block'
import mutator from '../mutator'
import octoClient from '../octoClient'
import {Utils} from '../utils'
import Menu from '../widgets/menu'
@ -21,7 +23,6 @@ type Props = {
const AddContentMenuItem = (props:Props): JSX.Element => {
const {card, type, cords} = props
const index = cords.x
const contentOrder = card.fields.contentOrder.slice()
const intl = useIntl()
const handler = contentRegistry.getHandler(type)
@ -43,11 +44,19 @@ const AddContentMenuItem = (props:Props): JSX.Element => {
const typeName = handler.getDisplayText(intl)
const description = intl.formatMessage({id: 'ContentBlock.addElement', defaultMessage: 'add {type}'}, {type: typeName})
mutator.performAsUndoGroup(async () => {
const insertedBlock = await mutator.insertBlock(newBlock.boardId, newBlock, description)
contentOrder.splice(index, 0, insertedBlock.id)
await mutator.changeCardContentOrder(card.boardId, card.id, card.fields.contentOrder, contentOrder, description)
})
const afterRedo = async (nb: Block) => {
const contentOrder = card.fields.contentOrder.slice()
contentOrder.splice(index, 0, nb.id)
await octoClient.patchBlock(card.boardId, card.id, {updatedFields: {contentOrder}})
}
const beforeUndo = async () => {
const contentOrder = card.fields.contentOrder.slice()
await octoClient.patchBlock(card.boardId, card.id, {updatedFields: {contentOrder}})
}
await mutator.insertBlock(newBlock.boardId, newBlock, description, afterRedo, beforeUndo)
}}
/>
)

View file

@ -6,7 +6,9 @@ import {useIntl, IntlShape} from 'react-intl'
import {IContentBlockWithCords, ContentBlock as ContentBlockType} from '../../blocks/contentBlock'
import {Card} from '../../blocks/card'
import {createTextBlock} from '../../blocks/textBlock'
import {Block} from '../../blocks/block'
import mutator from '../../mutator'
import octoClient from '../../octoClient'
import {useSortableWithGrip} from '../../hooks/sortable'
import ContentBlock from '../contentBlock'
@ -25,19 +27,26 @@ type Props = {
readonly: boolean
}
function addTextBlock(card: Card, intl: IntlShape, text: string): void {
async function addTextBlock(card: Card, intl: IntlShape, text: string): Promise<Block> {
const block = createTextBlock()
block.parentId = card.id
block.boardId = card.boardId
block.title = text
mutator.performAsUndoGroup(async () => {
const description = intl.formatMessage({id: 'CardDetail.addCardText', defaultMessage: 'add card text'})
const insertedBlock = await mutator.insertBlock(block.boardId, block, description)
const description = intl.formatMessage({id: 'CardDetail.addCardText', defaultMessage: 'add card text'})
const afterRedo = async (newBlock: Block) => {
const contentOrder = card.fields.contentOrder.slice()
contentOrder.push(insertedBlock.id)
await mutator.changeCardContentOrder(card.boardId, card.id, card.fields.contentOrder, contentOrder, description)
})
contentOrder.push(newBlock.id)
await octoClient.patchBlock(card.boardId, card.id, {updatedFields: {contentOrder}})
}
const beforeUndo = async () => {
const contentOrder = card.fields.contentOrder.slice()
await octoClient.patchBlock(card.boardId, card.id, {updatedFields: {contentOrder}})
}
return mutator.insertBlock(block.boardId, block, description, afterRedo, beforeUndo)
}
function moveBlock(card: Card, srcBlock: IContentBlockWithCords, dstBlock: IContentBlockWithCords, intl: IntlShape, moveTo: Position): void {

View file

@ -7,6 +7,7 @@ import {useIntl} from 'react-intl'
import {Block} from '../../blocks/block'
import {Card} from '../../blocks/card'
import {ContentHandler} from '../content/contentRegistry'
import octoClient from '../../octoClient'
import mutator from '../../mutator'
export type AddedBlock = {
@ -50,14 +51,20 @@ export const CardDetailProvider = (props: CardDetailProps): ReactElement => {
const typeName = handler.getDisplayText(intl)
const description = intl.formatMessage({id: 'ContentBlock.addElement', defaultMessage: 'add {type}'}, {type: typeName})
await mutator.performAsUndoGroup(async () => {
const insertedBlock = await mutator.insertBlock(block.boardId, block, description)
const contentOrder = card.fields.contentOrder.slice()
contentOrder.splice(index, 0, insertedBlock.id)
setLastAddedBlock({
id: insertedBlock.id,
autoAdded: auto,
})
await mutator.changeCardContentOrder(card.boardId, card.id, card.fields.contentOrder, contentOrder, description)
const afterRedo = async (newBlock: Block) => {
const contentOrder = card.fields.contentOrder.slice()
contentOrder.splice(index, 0, newBlock.id)
await octoClient.patchBlock(card.boardId, card.id, {updatedFields: {contentOrder}})
}
const beforeUndo = async () => {
const contentOrder = card.fields.contentOrder.slice()
await octoClient.patchBlock(card.boardId, card.id, {updatedFields: {contentOrder}})
}
const insertedBlock = await mutator.insertBlock(block.boardId, block, description, afterRedo, beforeUndo)
setLastAddedBlock({id: insertedBlock.id, autoAdded: auto})
})
}, [card.boardId, card.id, card.fields.contentOrder])

View file

@ -6,6 +6,7 @@ import {useIntl} from 'react-intl'
import {ImageBlock, createImageBlock} from '../../blocks/imageBlock'
import {sendFlashMessage} from '../flashMessages'
import {Block} from '../../blocks/block'
import octoClient from '../../octoClient'
import mutator from '../../mutator'
@ -45,13 +46,18 @@ export default function useImagePaste(boardId: string, cardId: string, contentOr
sendFlashMessage({content: intl.formatMessage({id: 'imagePaste.upload-failed', defaultMessage: 'Some files not uploaded. File size limit reached'}), severity: 'normal'})
}
mutator.performAsUndoGroup(async () => {
const newContentBlocks = await mutator.insertBlocks(boardId, blocksToInsert, 'pasted images')
const afterRedo = async (newBlocks: Block[]) => {
const newContentOrder = JSON.parse(JSON.stringify(contentOrder))
newContentOrder.push(...newContentBlocks.map((b: ImageBlock) => b.id))
newContentOrder.push(...newBlocks.map((b: Block) => b.id))
await octoClient.patchBlock(boardId, cardId, {updatedFields: {contentOrder: newContentOrder}})
}
await mutator.changeCardContentOrder(boardId, cardId, contentOrder, newContentOrder, 'paste image')
})
const beforeUndo = async () => {
const newContentOrder = JSON.parse(JSON.stringify(contentOrder))
await octoClient.patchBlock(boardId, cardId, {updatedFields: {contentOrder: newContentOrder}})
}
await mutator.insertBlocks(boardId, blocksToInsert, 'pasted images', afterRedo, beforeUndo)
}, [cardId, contentOrder, boardId])
const onDrop = useCallback((event: DragEvent): void => {