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() expect(container).toMatchSnapshot()
const buttonElement = screen.getByRole('button', {name: 'text'}) const buttonElement = screen.getByRole('button', {name: 'text'})
userEvent.click(buttonElement) userEvent.click(buttonElement)
await waitFor(() => expect(mockedMutator.performAsUndoGroup).toBeCalled()) await waitFor(() => expect(mockedMutator.insertBlock).toBeCalled())
}) })
test('return a checkbox menu item', async () => { test('return a checkbox menu item', async () => {
@ -83,7 +83,7 @@ describe('components/addContentMenuItem', () => {
expect(container).toMatchSnapshot() expect(container).toMatchSnapshot()
const buttonElement = screen.getByRole('button', {name: 'checkbox'}) const buttonElement = screen.getByRole('button', {name: 'checkbox'})
userEvent.click(buttonElement) userEvent.click(buttonElement)
await waitFor(() => expect(mockedMutator.performAsUndoGroup).toBeCalled()) await waitFor(() => expect(mockedMutator.insertBlock).toBeCalled())
}) })
test('return a divider menu item', async () => { test('return a divider menu item', async () => {
@ -99,7 +99,7 @@ describe('components/addContentMenuItem', () => {
expect(container).toMatchSnapshot() expect(container).toMatchSnapshot()
const buttonElement = screen.getByRole('button', {name: 'divider'}) const buttonElement = screen.getByRole('button', {name: 'divider'})
userEvent.click(buttonElement) 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', () => { 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 {BlockTypes} from '../blocks/block'
import {Card} from '../blocks/card' import {Card} from '../blocks/card'
import {Block} from '../blocks/block'
import mutator from '../mutator' import mutator from '../mutator'
import octoClient from '../octoClient'
import {Utils} from '../utils' import {Utils} from '../utils'
import Menu from '../widgets/menu' import Menu from '../widgets/menu'
@ -21,7 +23,6 @@ type Props = {
const AddContentMenuItem = (props:Props): JSX.Element => { const AddContentMenuItem = (props:Props): JSX.Element => {
const {card, type, cords} = props const {card, type, cords} = props
const index = cords.x const index = cords.x
const contentOrder = card.fields.contentOrder.slice()
const intl = useIntl() const intl = useIntl()
const handler = contentRegistry.getHandler(type) const handler = contentRegistry.getHandler(type)
@ -43,11 +44,19 @@ const AddContentMenuItem = (props:Props): JSX.Element => {
const typeName = handler.getDisplayText(intl) const typeName = handler.getDisplayText(intl)
const description = intl.formatMessage({id: 'ContentBlock.addElement', defaultMessage: 'add {type}'}, {type: typeName}) const description = intl.formatMessage({id: 'ContentBlock.addElement', defaultMessage: 'add {type}'}, {type: typeName})
mutator.performAsUndoGroup(async () => {
const insertedBlock = await mutator.insertBlock(newBlock.boardId, newBlock, description) const afterRedo = async (nb: Block) => {
contentOrder.splice(index, 0, insertedBlock.id) const contentOrder = card.fields.contentOrder.slice()
await mutator.changeCardContentOrder(card.boardId, card.id, card.fields.contentOrder, contentOrder, description) 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 {IContentBlockWithCords, ContentBlock as ContentBlockType} from '../../blocks/contentBlock'
import {Card} from '../../blocks/card' import {Card} from '../../blocks/card'
import {createTextBlock} from '../../blocks/textBlock' import {createTextBlock} from '../../blocks/textBlock'
import {Block} from '../../blocks/block'
import mutator from '../../mutator' import mutator from '../../mutator'
import octoClient from '../../octoClient'
import {useSortableWithGrip} from '../../hooks/sortable' import {useSortableWithGrip} from '../../hooks/sortable'
import ContentBlock from '../contentBlock' import ContentBlock from '../contentBlock'
@ -25,19 +27,26 @@ type Props = {
readonly: boolean 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() const block = createTextBlock()
block.parentId = card.id block.parentId = card.id
block.boardId = card.boardId block.boardId = card.boardId
block.title = text block.title = text
mutator.performAsUndoGroup(async () => {
const description = intl.formatMessage({id: 'CardDetail.addCardText', defaultMessage: 'add card text'}) const description = intl.formatMessage({id: 'CardDetail.addCardText', defaultMessage: 'add card text'})
const insertedBlock = await mutator.insertBlock(block.boardId, block, description)
const afterRedo = async (newBlock: Block) => {
const contentOrder = card.fields.contentOrder.slice() const contentOrder = card.fields.contentOrder.slice()
contentOrder.push(insertedBlock.id) contentOrder.push(newBlock.id)
await mutator.changeCardContentOrder(card.boardId, card.id, card.fields.contentOrder, contentOrder, description) 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 { 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 {Block} from '../../blocks/block'
import {Card} from '../../blocks/card' import {Card} from '../../blocks/card'
import {ContentHandler} from '../content/contentRegistry' import {ContentHandler} from '../content/contentRegistry'
import octoClient from '../../octoClient'
import mutator from '../../mutator' import mutator from '../../mutator'
export type AddedBlock = { export type AddedBlock = {
@ -50,14 +51,20 @@ export const CardDetailProvider = (props: CardDetailProps): ReactElement => {
const typeName = handler.getDisplayText(intl) const typeName = handler.getDisplayText(intl)
const description = intl.formatMessage({id: 'ContentBlock.addElement', defaultMessage: 'add {type}'}, {type: typeName}) const description = intl.formatMessage({id: 'ContentBlock.addElement', defaultMessage: 'add {type}'}, {type: typeName})
await mutator.performAsUndoGroup(async () => { await mutator.performAsUndoGroup(async () => {
const insertedBlock = await mutator.insertBlock(block.boardId, block, description)
const afterRedo = async (newBlock: Block) => {
const contentOrder = card.fields.contentOrder.slice() const contentOrder = card.fields.contentOrder.slice()
contentOrder.splice(index, 0, insertedBlock.id) contentOrder.splice(index, 0, newBlock.id)
setLastAddedBlock({ await octoClient.patchBlock(card.boardId, card.id, {updatedFields: {contentOrder}})
id: insertedBlock.id, }
autoAdded: auto,
}) const beforeUndo = async () => {
await mutator.changeCardContentOrder(card.boardId, card.id, card.fields.contentOrder, contentOrder, description) 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]) }, [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 {ImageBlock, createImageBlock} from '../../blocks/imageBlock'
import {sendFlashMessage} from '../flashMessages' import {sendFlashMessage} from '../flashMessages'
import {Block} from '../../blocks/block'
import octoClient from '../../octoClient' import octoClient from '../../octoClient'
import mutator from '../../mutator' 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'}) sendFlashMessage({content: intl.formatMessage({id: 'imagePaste.upload-failed', defaultMessage: 'Some files not uploaded. File size limit reached'}), severity: 'normal'})
} }
mutator.performAsUndoGroup(async () => { const afterRedo = async (newBlocks: Block[]) => {
const newContentBlocks = await mutator.insertBlocks(boardId, blocksToInsert, 'pasted images')
const newContentOrder = JSON.parse(JSON.stringify(contentOrder)) 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]) }, [cardId, contentOrder, boardId])
const onDrop = useCallback((event: DragEvent): void => { const onDrop = useCallback((event: DragEvent): void => {