mirror of
https://github.com/mattermost/focalboard.git
synced 2024-11-24 08:22:29 +02:00
Undo grouping
This commit is contained in:
parent
25a1ebeda4
commit
b7ea5e677b
@ -545,6 +545,7 @@ class BoardComponent extends React.Component<Props, State> {
|
|||||||
Utils.assertValue(boardTree)
|
Utils.assertValue(boardTree)
|
||||||
|
|
||||||
if (draggedCards.length > 0) {
|
if (draggedCards.length > 0) {
|
||||||
|
mutator.beginUndoGroup()
|
||||||
for (const draggedCard of draggedCards) {
|
for (const draggedCard of draggedCards) {
|
||||||
Utils.log(`ondrop. Card: ${draggedCard.title}, column: ${optionId}`)
|
Utils.log(`ondrop. Card: ${draggedCard.title}, column: ${optionId}`)
|
||||||
const oldValue = draggedCard.properties[boardTree.groupByProperty.id]
|
const oldValue = draggedCard.properties[boardTree.groupByProperty.id]
|
||||||
@ -552,6 +553,7 @@ class BoardComponent extends React.Component<Props, State> {
|
|||||||
await mutator.changePropertyValue(draggedCard, boardTree.groupByProperty.id, optionId, 'drag card')
|
await mutator.changePropertyValue(draggedCard, boardTree.groupByProperty.id, optionId, 'drag card')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mutator.endUndoGroup()
|
||||||
} else if (draggedHeaderOption) {
|
} else if (draggedHeaderOption) {
|
||||||
Utils.log(`ondrop. Header option: ${draggedHeaderOption.value}, column: ${option?.value}`)
|
Utils.log(`ondrop. Header option: ${draggedHeaderOption.value}, column: ${option?.value}`)
|
||||||
Utils.assertValue(boardTree.groupByProperty)
|
Utils.assertValue(boardTree.groupByProperty)
|
||||||
@ -573,13 +575,15 @@ class BoardComponent extends React.Component<Props, State> {
|
|||||||
Utils.log(`onDropToCard: ${card.title}`)
|
Utils.log(`onDropToCard: ${card.title}`)
|
||||||
const {boardTree} = this.props
|
const {boardTree} = this.props
|
||||||
const {activeView} = boardTree
|
const {activeView} = boardTree
|
||||||
const {draggedCards, draggedHeaderOption} = this
|
const {draggedCards} = this
|
||||||
const optionId = card.properties[activeView.groupById]
|
const optionId = card.properties[activeView.groupById]
|
||||||
|
|
||||||
if (draggedCards.length < 1) {
|
if (draggedCards.length < 1) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutator.beginUndoGroup()
|
||||||
|
|
||||||
const cardOrder = boardTree.orderedCards().map((o) => o.id)
|
const cardOrder = boardTree.orderedCards().map((o) => o.id)
|
||||||
for (const draggedCard of draggedCards) {
|
for (const draggedCard of draggedCards) {
|
||||||
if (draggedCard.id === card.id) {
|
if (draggedCard.id === card.id) {
|
||||||
@ -604,6 +608,7 @@ class BoardComponent extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await mutator.changeViewCardOrder(activeView, cardOrder)
|
await mutator.changeViewCardOrder(activeView, cardOrder)
|
||||||
|
mutator.endUndoGroup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,28 +87,33 @@ class ViewHeader extends React.Component<Props, State> {
|
|||||||
const startCount = boardTree?.cards?.length
|
const startCount = boardTree?.cards?.length
|
||||||
let optionIndex = 0
|
let optionIndex = 0
|
||||||
|
|
||||||
|
mutator.beginUndoGroup()
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
const card = new MutableCard()
|
const card = new MutableCard()
|
||||||
card.parentId = boardTree.board.id
|
card.parentId = boardTree.board.id
|
||||||
card.properties = CardFilter.propertiesThatMeetFilterGroup(activeView.filter, board.cardProperties)
|
card.properties = CardFilter.propertiesThatMeetFilterGroup(activeView.filter, board.cardProperties)
|
||||||
|
card.title = `Test Card ${startCount + i + 1}`
|
||||||
|
card.icon = BlockIcons.shared.randomIcon()
|
||||||
|
|
||||||
if (boardTree.groupByProperty && boardTree.groupByProperty.options.length > 0) {
|
if (boardTree.groupByProperty && boardTree.groupByProperty.options.length > 0) {
|
||||||
// Cycle through options
|
// Cycle through options
|
||||||
const option = boardTree.groupByProperty.options[optionIndex]
|
const option = boardTree.groupByProperty.options[optionIndex]
|
||||||
optionIndex = (optionIndex + 1) % boardTree.groupByProperty.options.length
|
optionIndex = (optionIndex + 1) % boardTree.groupByProperty.options.length
|
||||||
card.properties[boardTree.groupByProperty.id] = option.id
|
card.properties[boardTree.groupByProperty.id] = option.id
|
||||||
card.title = `Test Card ${startCount + i + 1}`
|
|
||||||
card.icon = BlockIcons.shared.randomIcon()
|
|
||||||
}
|
}
|
||||||
await mutator.insertBlock(card, 'test add card')
|
await mutator.insertBlock(card, 'test add card')
|
||||||
}
|
}
|
||||||
|
mutator.endUndoGroup()
|
||||||
}
|
}
|
||||||
|
|
||||||
private async testRandomizeIcons() {
|
private async testRandomizeIcons() {
|
||||||
const {boardTree} = this.props
|
const {boardTree} = this.props
|
||||||
|
|
||||||
|
mutator.beginUndoGroup()
|
||||||
for (const card of boardTree.cards) {
|
for (const card of boardTree.cards) {
|
||||||
mutator.changeIcon(card, BlockIcons.shared.randomIcon(), 'randomize icon')
|
mutator.changeIcon(card, BlockIcons.shared.randomIcon(), 'randomize icon')
|
||||||
}
|
}
|
||||||
|
mutator.endUndoGroup()
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
|
@ -17,6 +17,16 @@ import {Utils} from './utils'
|
|||||||
// It also ensures that the Undo-manager is called for each action
|
// It also ensures that the Undo-manager is called for each action
|
||||||
//
|
//
|
||||||
class Mutator {
|
class Mutator {
|
||||||
|
private undoGroupId?: string
|
||||||
|
|
||||||
|
beginUndoGroup() {
|
||||||
|
this.undoGroupId = Utils.createGuid()
|
||||||
|
}
|
||||||
|
|
||||||
|
endUndoGroup() {
|
||||||
|
this.undoGroupId = undefined
|
||||||
|
}
|
||||||
|
|
||||||
async updateBlock(newBlock: IBlock, oldBlock: IBlock, description: string): Promise<void> {
|
async updateBlock(newBlock: IBlock, oldBlock: IBlock, description: string): Promise<void> {
|
||||||
await undoManager.perform(
|
await undoManager.perform(
|
||||||
async () => {
|
async () => {
|
||||||
@ -26,6 +36,7 @@ class Mutator {
|
|||||||
await octoClient.updateBlock(oldBlock)
|
await octoClient.updateBlock(oldBlock)
|
||||||
},
|
},
|
||||||
description,
|
description,
|
||||||
|
this.undoGroupId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,6 +49,7 @@ class Mutator {
|
|||||||
await octoClient.updateBlocks(oldBlocks)
|
await octoClient.updateBlocks(oldBlocks)
|
||||||
},
|
},
|
||||||
description,
|
description,
|
||||||
|
this.undoGroupId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,6 +64,7 @@ class Mutator {
|
|||||||
await octoClient.deleteBlock(block.id)
|
await octoClient.deleteBlock(block.id)
|
||||||
},
|
},
|
||||||
description,
|
description,
|
||||||
|
this.undoGroupId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,6 +81,7 @@ class Mutator {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
description,
|
description,
|
||||||
|
this.undoGroupId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,6 +100,7 @@ class Mutator {
|
|||||||
await afterUndo?.()
|
await afterUndo?.()
|
||||||
},
|
},
|
||||||
description,
|
description,
|
||||||
|
this.undoGroupId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,6 +472,7 @@ class Mutator {
|
|||||||
await octoClient.deleteBlock(block.id)
|
await octoClient.deleteBlock(block.id)
|
||||||
},
|
},
|
||||||
'add image',
|
'add image',
|
||||||
|
this.undoGroupId
|
||||||
)
|
)
|
||||||
|
|
||||||
return block
|
return block
|
||||||
|
@ -5,6 +5,7 @@ interface UndoCommand {
|
|||||||
undo: () => Promise<void>
|
undo: () => Promise<void>
|
||||||
redo: () => Promise<void>
|
redo: () => Promise<void>
|
||||||
description?: string
|
description?: string
|
||||||
|
groupId?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -59,10 +60,11 @@ class UndoManager {
|
|||||||
redo: () => Promise<void>,
|
redo: () => Promise<void>,
|
||||||
undo: () => Promise<void>,
|
undo: () => Promise<void>,
|
||||||
description?: string,
|
description?: string,
|
||||||
|
groupId?: string,
|
||||||
isDiscardable = false,
|
isDiscardable = false,
|
||||||
): Promise<UndoManager> {
|
): Promise<UndoManager> {
|
||||||
await redo()
|
await redo()
|
||||||
return this.registerUndo({undo, redo}, description, isDiscardable)
|
return this.registerUndo({undo, redo}, description, groupId, isDiscardable)
|
||||||
}
|
}
|
||||||
|
|
||||||
registerUndo(
|
registerUndo(
|
||||||
@ -71,6 +73,7 @@ class UndoManager {
|
|||||||
redo: () => Promise<void>
|
redo: () => Promise<void>
|
||||||
},
|
},
|
||||||
description?: string,
|
description?: string,
|
||||||
|
groupId?: string,
|
||||||
isDiscardable = false,
|
isDiscardable = false,
|
||||||
): UndoManager {
|
): UndoManager {
|
||||||
if (this.isExecuting) {
|
if (this.isExecuting) {
|
||||||
@ -93,6 +96,7 @@ class UndoManager {
|
|||||||
undo: command.undo,
|
undo: command.undo,
|
||||||
redo: command.redo,
|
redo: command.redo,
|
||||||
description,
|
description,
|
||||||
|
groupId,
|
||||||
}
|
}
|
||||||
this.commands.push(internalCommand)
|
this.commands.push(internalCommand)
|
||||||
|
|
||||||
@ -115,13 +119,20 @@ class UndoManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async undo() {
|
async undo() {
|
||||||
const command = this.commands[this.index]
|
if (this.isExecuting) {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
let command = this.commands[this.index]
|
||||||
if (!command) {
|
if (!command) {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.execute(command, 'undo')
|
const currentGroupId = command.groupId
|
||||||
this.index -= 1
|
do {
|
||||||
|
await this.execute(command, 'undo')
|
||||||
|
this.index -= 1
|
||||||
|
command = this.commands[this.index]
|
||||||
|
} while (this.index >= 0 && currentGroupId && currentGroupId === command.groupId)
|
||||||
|
|
||||||
if (this.onStateDidChange) {
|
if (this.onStateDidChange) {
|
||||||
this.onStateDidChange()
|
this.onStateDidChange()
|
||||||
@ -131,13 +142,20 @@ class UndoManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async redo() {
|
async redo() {
|
||||||
const command = this.commands[this.index + 1]
|
if (this.isExecuting) {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
let command = this.commands[this.index + 1]
|
||||||
if (!command) {
|
if (!command) {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.execute(command, 'redo')
|
const currentGroupId = command.groupId
|
||||||
this.index += 1
|
do {
|
||||||
|
await this.execute(command, 'redo')
|
||||||
|
this.index += 1
|
||||||
|
command = this.commands[this.index + 1]
|
||||||
|
} while (this.index < this.commands.length && currentGroupId && currentGroupId === command.groupId)
|
||||||
|
|
||||||
if (this.onStateDidChange) {
|
if (this.onStateDidChange) {
|
||||||
this.onStateDidChange()
|
this.onStateDidChange()
|
||||||
|
Loading…
Reference in New Issue
Block a user