Skip to content

fix(wework): prevent duplicate composer paste - #2053

Merged
qdaxb merged 2 commits into
mainfrom
fix/wework-duplicate-composer-paste
Jul 19, 2026
Merged

qdaxb merged 2 commits into
mainfrom
fix/wework-duplicate-composer-paste

Conversation

@qdaxb

@qdaxb qdaxb commented Jul 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • route ordinary text paste through ProseMirror's handlePaste pipeline so one clipboard event produces one editor transaction
  • keep file and long-text attachment interception in the DOM paste hook
  • preserve multiline plain text when the clipboard also contains rich HTML
  • document the single-insertion behavior in Chinese and English

Root cause

The composer manually mutated the document from the low-level DOM paste hook. In Wework's WebKit runtime this could overlap with ProseMirror's own paste lifecycle and intermittently insert the same clipboard payload twice. Rich clipboard payloads also need to use their plain-text representation because the composer schema contains one paragraph with hard breaks.

Validation

  • pnpm --filter wework test — 180 files, 1816 tests passed
  • pnpm --filter wework typecheck
  • focused composer and attachment regression suite — 110 tests passed
  • Prettier, ESLint, typography, and pre-push checks passed
  • isolated real-Tauri flow: empty composer → paste three unique multiline markers once → submit → one user bubble containing each marker once

Screenshot review chain

The isolated Tauri artifacts are retained under wework/test-results/ai-verify/review-duplicate-composer-paste/ in the verification workspace:

  1. 01-empty-composer.png
  2. 02-after-single-paste.png
  3. 03-after-submit.png

Summary by CodeRabbit

  • Bug Fixes
    • Prevented duplicate content insertion when pasting into the conversation composer.
    • Preserved expected line breaks when pasting multiline plain text and rich text.
    • Normalized Windows-style line endings during paste.
    • When the clipboard contains both plain and rich text, the pasted content is inserted only once.
  • Documentation
    • Updated the English and Chinese user guides to clarify multiline paste behavior and how mixed plain/rich-text clipboard content is handled.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d0cb83e3-9244-4bb2-97d6-ef76fe39ec2a

📥 Commits

Reviewing files that changed from the base of the PR and between e0d7e27 and 411a2a8.

📒 Files selected for processing (1)
  • wework/src/components/chat/composer/ComposerProseMirrorEditor.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • wework/src/components/chat/composer/ComposerProseMirrorEditor.tsx

📝 Walkthrough

Walkthrough

The composer’s paste handling now uses a dedicated ProseMirror handler. Tests cover single insertion and multiline rich-text pastes, while English and Chinese documentation describe line-break normalization and mixed clipboard content behavior.

Changes

Composer paste behavior

Layer / File(s) Summary
Dedicated paste insertion handler
wework/src/components/chat/composer/ComposerProseMirrorEditor.tsx
Clipboard text insertion is handled by handlePaste, while the DOM paste callback delegates to onPaste.
Paste behavior tests and documentation
wework/src/components/chat/composer/ComposerProseMirrorEditor.test.tsx, docs/{en,zh}/user-guide/chat/managing-tasks.md
Tests verify single insertion and preserved multiline text; documentation describes line-break normalization and mixed plain/rich clipboard content.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • wecode-ai/Wegent#1967: Related ComposerProseMirrorEditor paste-handling changes and multiline preservation tests.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: fixing duplicate paste insertion in the WeWork composer.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/wework-duplicate-composer-paste

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qdaxb
qdaxb marked this pull request as ready for review July 19, 2026 17:19

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
wework/src/components/chat/composer/ComposerProseMirrorEditor.tsx (1)

149-160: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Restore native paste scrolling and metadata.

When overriding ProseMirror's default paste behavior, manually dispatching the transaction loses the native auto-scroll and event metadata. Chaining scrollIntoView() ensures the caret remains visible if the user pastes a large block of multiline text, and setting the metadata ensures history or input plugins correctly categorize the paste event.

♻️ Proposed refactor
       handlePaste(view, event) {
         const text =
           event.clipboardData?.getData('text/plain') || event.clipboardData?.getData('text')
         if (!text) return false
         const paragraph = createComposerDocument(text).firstChild
         if (!paragraph) return false
-        view.dispatch(view.state.tr.replaceSelection(new Slice(paragraph.content, 0, 0)))
+        const tr = view.state.tr.replaceSelection(new Slice(paragraph.content, 0, 0))
+        view.dispatch(tr.setMeta('paste', true).setMeta('uiEvent', 'paste').scrollIntoView())
         return true
       },
       handleDOMEvents: {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wework/src/components/chat/composer/ComposerProseMirrorEditor.tsx` around
lines 149 - 160, The custom paste handler in handlePaste should preserve native
paste behavior by chaining scrollIntoView() onto the replacement transaction and
setting the transaction’s paste/input metadata before dispatching it. Keep the
existing text extraction, selection replacement, and handled-event flow
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@wework/src/components/chat/composer/ComposerProseMirrorEditor.tsx`:
- Around line 149-160: The custom paste handler in handlePaste should preserve
native paste behavior by chaining scrollIntoView() onto the replacement
transaction and setting the transaction’s paste/input metadata before
dispatching it. Keep the existing text extraction, selection replacement, and
handled-event flow unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dd5e4c34-ce41-448b-bace-ffc404e6e3d7

📥 Commits

Reviewing files that changed from the base of the PR and between 01a4ce2 and e0d7e27.

📒 Files selected for processing (4)
  • docs/en/user-guide/chat/managing-tasks.md
  • docs/zh/user-guide/chat/managing-tasks.md
  • wework/src/components/chat/composer/ComposerProseMirrorEditor.test.tsx
  • wework/src/components/chat/composer/ComposerProseMirrorEditor.tsx

@qdaxb
qdaxb merged commit d760c26 into main Jul 19, 2026
29 checks passed
@qdaxb
qdaxb deleted the fix/wework-duplicate-composer-paste branch July 19, 2026 20:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant