diff --git a/webapp/cypress/integration/createBoard.ts b/webapp/cypress/integration/createBoard.ts
index 895ab9fcb..b96123f85 100644
--- a/webapp/cypress/integration/createBoard.ts
+++ b/webapp/cypress/integration/createBoard.ts
@@ -183,4 +183,42 @@ describe('Create and delete board / card', () => {
cy.get('.Kanban').invoke('scrollLeft').should('equal', 0)
})
+
+ it('GH-2520 make cut/undo/redo work in comments', () => {
+ const isMAC = navigator.userAgent.indexOf("Mac") !== -1
+ const ctrlKey = isMAC ? 'meta' : 'ctrl'
+ // Visit a page and create new empty board
+ cy.visit('/')
+ cy.uiCreateEmptyBoard()
+
+ // Create card
+ cy.log('**Create card**')
+ cy.get('.ViewHeader').contains('New').click()
+ cy.get('.CardDetail').should('exist')
+
+ cy.wait(1000)
+
+ cy.log('**Add comment**')
+ cy.get('.CommentsList').
+ findAllByTestId('preview-element').
+ click().
+ get('.CommentsList .MarkdownEditorInput').
+ type('Test Text')
+
+ cy.log('**Cut comment**')
+ cy.get('.CommentsList .MarkdownEditorInput').
+ type('{selectAll}').
+ trigger('cut').
+ should('have.text', '')
+
+ cy.log('**Undo comment**')
+ cy.get('.CommentsList .MarkdownEditorInput').
+ type(`{${ctrlKey}+z}`).
+ should('have.text', 'Test Text')
+
+ cy.log('**Redo comment**')
+ cy.get('.CommentsList .MarkdownEditorInput').
+ type(`{shift+${ctrlKey}+z}`).
+ should('have.text', '')
+ })
})
diff --git a/webapp/src/components/__snapshots__/cardDialog.test.tsx.snap b/webapp/src/components/__snapshots__/cardDialog.test.tsx.snap
index 536153a8d..702396943 100644
--- a/webapp/src/components/__snapshots__/cardDialog.test.tsx.snap
+++ b/webapp/src/components/__snapshots__/cardDialog.test.tsx.snap
@@ -139,51 +139,6 @@ exports[`components/cardDialog already following card 1`] = `
class="octo-editor-preview octo-placeholder"
data-testid="preview-element"
/>
-
@@ -211,51 +166,6 @@ exports[`components/cardDialog already following card 1`] = `
class="octo-editor-preview octo-placeholder"
data-testid="preview-element"
/>
-
@@ -883,51 +793,6 @@ exports[`components/cardDialog return cardDialog menu content 1`] = `
class="octo-editor-preview octo-placeholder"
data-testid="preview-element"
/>
-
@@ -955,51 +820,6 @@ exports[`components/cardDialog return cardDialog menu content 1`] = `
class="octo-editor-preview octo-placeholder"
data-testid="preview-element"
/>
-
@@ -1166,51 +986,6 @@ exports[`components/cardDialog return cardDialog menu content and cancel delete
class="octo-editor-preview octo-placeholder"
data-testid="preview-element"
/>
-
@@ -1238,51 +1013,6 @@ exports[`components/cardDialog return cardDialog menu content and cancel delete
class="octo-editor-preview octo-placeholder"
data-testid="preview-element"
/>
-
@@ -1449,51 +1179,6 @@ exports[`components/cardDialog should match snapshot 1`] = `
class="octo-editor-preview octo-placeholder"
data-testid="preview-element"
/>
-
@@ -1521,51 +1206,6 @@ exports[`components/cardDialog should match snapshot 1`] = `
class="octo-editor-preview octo-placeholder"
data-testid="preview-element"
/>
-
diff --git a/webapp/src/components/__snapshots__/centerPanel.test.tsx.snap b/webapp/src/components/__snapshots__/centerPanel.test.tsx.snap
index 879961dbf..2bf355666 100644
--- a/webapp/src/components/__snapshots__/centerPanel.test.tsx.snap
+++ b/webapp/src/components/__snapshots__/centerPanel.test.tsx.snap
@@ -88,53 +88,6 @@ exports[`components/centerPanel Clicking on the Hidden card count should open a
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -833,53 +786,6 @@ exports[`components/centerPanel return centerPanel and click on card to show car
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -1433,53 +1339,6 @@ exports[`components/centerPanel return centerPanel and click on new card to edit
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -2111,53 +1970,6 @@ exports[`components/centerPanel return centerPanel and press touch 1 with readon
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -2584,53 +2396,6 @@ exports[`components/centerPanel return centerPanel and press touch ctrl+d for on
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -3279,53 +3044,6 @@ exports[`components/centerPanel return centerPanel and press touch del for one c
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -3974,53 +3692,6 @@ exports[`components/centerPanel return centerPanel and press touch esc for one c
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -4669,53 +4340,6 @@ exports[`components/centerPanel return centerPanel and press touch esc for one c
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -5364,53 +4988,6 @@ exports[`components/centerPanel return centerPanel and press touch esc for two c
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -6059,53 +5636,6 @@ exports[`components/centerPanel return centerPanel and press touch esc for two c
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -6754,53 +6284,6 @@ exports[`components/centerPanel return centerPanel and press touch esc for two c
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -7449,53 +6932,6 @@ exports[`components/centerPanel return centerPanel and select one card and click
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -8144,53 +7580,6 @@ exports[`components/centerPanel return centerPanel and select one card and click
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -8839,53 +8228,6 @@ exports[`components/centerPanel should match snapshot for Gallery 1`] = `
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -9161,53 +8503,6 @@ exports[`components/centerPanel should match snapshot for Kanban 1`] = `
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -10246,53 +9541,6 @@ exports[`components/centerPanel should match snapshot for Table 1`] = `
class="octo-editor-preview"
data-testid="preview-element"
/>
-
diff --git a/webapp/src/components/__snapshots__/contentBlock.test.tsx.snap b/webapp/src/components/__snapshots__/contentBlock.test.tsx.snap
index 3b53de7bb..7bb6673a8 100644
--- a/webapp/src/components/__snapshots__/contentBlock.test.tsx.snap
+++ b/webapp/src/components/__snapshots__/contentBlock.test.tsx.snap
@@ -472,53 +472,6 @@ exports[`components/contentBlock should match snapshot with textBlock 1`] = `
class="octo-editor-preview"
data-testid="preview-element"
/>
-
-
`;
@@ -67,53 +22,6 @@ exports[`components/markdownEditor should match snapshot with initial text 1`] =
class="octo-editor-preview"
data-testid="preview-element"
/>
-
`;
@@ -122,55 +30,7 @@ exports[`components/markdownEditor should match snapshot with on click on previe
`;
diff --git a/webapp/src/components/__snapshots__/viewTitle.test.tsx.snap b/webapp/src/components/__snapshots__/viewTitle.test.tsx.snap
index e61ad82c4..606e953a5 100644
--- a/webapp/src/components/__snapshots__/viewTitle.test.tsx.snap
+++ b/webapp/src/components/__snapshots__/viewTitle.test.tsx.snap
@@ -152,53 +152,6 @@ exports[`components/viewTitle should match snapshot 1`] = `
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -246,53 +199,6 @@ exports[`components/viewTitle should match snapshot readonly 1`] = `
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -356,53 +262,6 @@ exports[`components/viewTitle show description 1`] = `
class="octo-editor-preview"
data-testid="preview-element"
/>
-
diff --git a/webapp/src/components/__snapshots__/workspace.test.tsx.snap b/webapp/src/components/__snapshots__/workspace.test.tsx.snap
index 83046f0c5..1aef03022 100644
--- a/webapp/src/components/__snapshots__/workspace.test.tsx.snap
+++ b/webapp/src/components/__snapshots__/workspace.test.tsx.snap
@@ -362,53 +362,6 @@ exports[`src/components/workspace return workspace and showcard 1`] = `
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -931,53 +884,6 @@ exports[`src/components/workspace return workspace readonly and showcard 1`] = `
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -1597,53 +1503,6 @@ exports[`src/components/workspace should match snapshot 1`] = `
class="octo-editor-preview"
data-testid="preview-element"
/>
-
@@ -2166,53 +2025,6 @@ exports[`src/components/workspace should match snapshot with readonly 1`] = `
class="octo-editor-preview"
data-testid="preview-element"
/>
-
diff --git a/webapp/src/components/cardDetail/__snapshots__/cardDetailContents.test.tsx.snap b/webapp/src/components/cardDetail/__snapshots__/cardDetailContents.test.tsx.snap
index a91ee675c..feb26362a 100644
--- a/webapp/src/components/cardDetail/__snapshots__/cardDetailContents.test.tsx.snap
+++ b/webapp/src/components/cardDetail/__snapshots__/cardDetailContents.test.tsx.snap
@@ -22,51 +22,6 @@ exports[`components/cardDetail/cardDetailContents should match snapshot 1`] = `
Add a description...
-
diff --git a/webapp/src/components/content/__snapshots__/textElement.test.tsx.snap b/webapp/src/components/content/__snapshots__/textElement.test.tsx.snap
index 203758646..a1df4675d 100644
--- a/webapp/src/components/content/__snapshots__/textElement.test.tsx.snap
+++ b/webapp/src/components/content/__snapshots__/textElement.test.tsx.snap
@@ -9,51 +9,6 @@ exports[`components/content/TextElement return a textElement 1`] = `
class="octo-editor-preview octo-placeholder"
data-testid="preview-element"
/>
-
`;
diff --git a/webapp/src/components/markdownEditor.tsx b/webapp/src/components/markdownEditor.tsx
index 2359d93f4..8f3f6dc1b 100644
--- a/webapp/src/components/markdownEditor.tsx
+++ b/webapp/src/components/markdownEditor.tsx
@@ -64,8 +64,7 @@ const MarkdownEditor = (props: Props): JSX.Element => {
const element = (
- {!isEditing && previewElement}
- {editorElement}
+ {isEditing ? editorElement : previewElement}
)
diff --git a/webapp/src/components/markdownEditorInput/markdownEditorInput.scss b/webapp/src/components/markdownEditorInput/markdownEditorInput.scss
index de4635b10..83e1388ae 100644
--- a/webapp/src/components/markdownEditorInput/markdownEditorInput.scss
+++ b/webapp/src/components/markdownEditorInput/markdownEditorInput.scss
@@ -4,10 +4,6 @@
align-items: center;
}
- &--IsNotEditing {
- display: none;
- }
-
span[data-testid='mentionText'] {
background: rgba(var(--button-bg-rgb), 0.16);
border-radius: 4px;
diff --git a/webapp/src/components/markdownEditorInput/markdownEditorInput.tsx b/webapp/src/components/markdownEditorInput/markdownEditorInput.tsx
index 9bcd50e84..77686006f 100644
--- a/webapp/src/components/markdownEditorInput/markdownEditorInput.tsx
+++ b/webapp/src/components/markdownEditorInput/markdownEditorInput.tsx
@@ -50,7 +50,7 @@ type Props = {
}
const MarkdownEditorInput = (props: Props): ReactElement => {
- const {onChange, onFocus, onBlur, initialText, id, isEditing} = props
+ const {onChange, onFocus, onBlur, initialText, id} = props
const boardUsers = useAppSelector(getBoardUsersList)
const board = useAppSelector(getCurrentBoard)
const clientConfig = useAppSelector(getClientConfig)
@@ -92,24 +92,7 @@ const MarkdownEditorInput = (props: Props): ReactElement => {
return EditorState.moveSelectionToEnd(state)
}
- const [editorState, setEditorState] = useState(() => {
- return generateEditorState(initialText)
- })
-
- const [initialTextCache, setInitialTextCache] = useState(initialText)
-
- // avoiding stale closure
- useEffect(() => {
- // only change editor state when initialText actually changes from one defined value to another.
- // This is needed to make the mentions plugin work. For some reason, if we don't check
- // for this if condition here, mentions don't work. I suspect it's because without
- // the in condition, we're changing editor state twice during component initialization
- // and for some reason it causes mentions to not show up.
- if (initialText && initialText !== initialTextCache) {
- setEditorState(generateEditorState(initialText || ''))
- setInitialTextCache(initialText)
- }
- }, [initialText])
+ const [editorState, setEditorState] = useState(() => generateEditorState(initialText))
const [isMentionPopoverOpen, setIsMentionPopoverOpen] = useState(false)
const [isEmojiPopoverOpen, setIsEmojiPopoverOpen] = useState(false)
@@ -132,16 +115,13 @@ const MarkdownEditorInput = (props: Props): ReactElement => {
return {plugins, MentionSuggestions, EmojiSuggestions}
}, [])
- useEffect(() => {
- if (isEditing) {
- if (initialText === '') {
- setEditorState(EditorState.createEmpty())
- } else {
- setEditorState(EditorState.moveSelectionToEnd(editorState))
- }
- setTimeout(() => ref.current?.focus(), 200)
- }
- }, [isEditing, initialText])
+ const onEditorStateChange = useCallback((newEditorState: EditorState) => {
+ // newEditorState.
+ const newText = newEditorState.getCurrentContent().getPlainText()
+
+ onChange && onChange(newText)
+ setEditorState(newEditorState)
+ }, [onChange])
const customKeyBindingFn = useCallback((e: React.KeyboardEvent) => {
if (isMentionPopoverOpen || isEmojiPopoverOpen) {
@@ -152,14 +132,36 @@ const MarkdownEditorInput = (props: Props): ReactElement => {
return 'editor-blur'
}
+ if(getDefaultKeyBinding(e) === 'undo'){
+ return 'editor-undo'
+ }
+
+ if(getDefaultKeyBinding(e) === 'redo'){
+ return 'editor-redo'
+ }
+
return getDefaultKeyBinding(e as any)
}, [isEmojiPopoverOpen, isMentionPopoverOpen])
- const handleKeyCommand = useCallback((command: string): DraftHandleValue => {
+ const handleKeyCommand = useCallback((command: string, currentState: EditorState): DraftHandleValue => {
if (command === 'editor-blur') {
ref.current?.blur()
return 'handled'
}
+
+ if(command === 'editor-redo'){
+ const selectionRemovedState = EditorState.redo(currentState)
+ onEditorStateChange(EditorState.redo(selectionRemovedState))
+
+ return 'handled'
+ }
+
+ if(command === 'editor-undo'){
+ const selectionRemovedState = EditorState.undo(currentState)
+ onEditorStateChange(EditorState.undo(selectionRemovedState))
+
+ return 'handled'
+ }
return 'not-handled'
}, [])
@@ -169,13 +171,6 @@ const MarkdownEditorInput = (props: Props): ReactElement => {
onBlur && onBlur(text)
}, [editorState, onBlur])
- const onEditorStateChange = useCallback((newEditorState: EditorState) => {
- const newText = newEditorState.getCurrentContent().getPlainText()
-
- onChange && onChange(newText)
- setEditorState(newEditorState)
- }, [onChange])
-
const onMentionPopoverOpenChange = useCallback((open: boolean) => {
setIsMentionPopoverOpen(open)
}, [])
@@ -192,10 +187,7 @@ const MarkdownEditorInput = (props: Props): ReactElement => {
debouncedLoadSuggestion(value)
}, [suggestions])
- let className = 'MarkdownEditorInput'
- if (!isEditing) {
- className += ' MarkdownEditorInput--IsNotEditing'
- }
+ const className = 'MarkdownEditorInput'
return (