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 (