feat: Standardize rich editor across all channels (#12600)

# Pull Request Template

## Description

This PR includes,

1. **Channel-specific formatting and menu options** for the rich reply
editor.
2. **Removal of the plain reply editor** and full **standardization** on
the rich reply editor across all channels.
3. **Fix for multiple canned responses insertion:**
* **Before:** The plain editor only allowed inserting canned responses
at the beginning of a message, making it impossible to combine multiple
canned responses in a single reply. This caused inconsistent behavior
across the app.
* **Solution:** Replaced the plain reply editor with the rich
(ProseMirror) editor to ensure a unified experience. Agents can now
insert multiple canned responses at any cursor position.
4. **Floating editor menu** for the reply box to improve accessibility
and overall user experience.
5. **New Strikethrough formatting option** added to the editor menu.

---

**Editor repo PR**:
https://github.com/chatwoot/prosemirror-schema/pull/36

Fixes https://github.com/chatwoot/chatwoot/issues/12517,
[CW-5924](https://linear.app/chatwoot/issue/CW-5924/standardize-the-editor),
[CW-5679](https://linear.app/chatwoot/issue/CW-5679/allow-inserting-multiple-canned-responses-in-a-single-message)

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## How Has This Been Tested?

### Screenshot
**Dark**
<img width="850" height="345" alt="image"
src="https://github.com/user-attachments/assets/47748e6c-380f-44a3-9e3b-c27e0c830bd0"
/>

**Light**
<img width="850" height="345" alt="image"
src="https://github.com/user-attachments/assets/6746cf32-bf63-4280-a5bd-bbd42c3cbe84"
/>


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Pranav <pranav@chatwoot.com>
Co-authored-by: Vinay Keerthi <11478411+stonecharioteer@users.noreply.github.com>
This commit is contained in:
Sivin Varghese
2025-12-08 14:43:45 +05:30
committed by GitHub
parent eb759255d8
commit 399c91adaa
33 changed files with 1351 additions and 334 deletions

View File

@@ -10,8 +10,8 @@ RSpec.describe MessageContentPresenter do
let(:content_type) { 'text' }
let(:content) { 'Regular message' }
it 'returns regular content' do
expect(presenter.outgoing_content).to eq('Regular message')
it 'returns content transformed for channel (HTML for WebWidget)' do
expect(presenter.outgoing_content).to eq("<p>Regular message</p>\n")
end
end
@@ -23,8 +23,8 @@ RSpec.describe MessageContentPresenter do
allow(message.inbox).to receive(:web_widget?).and_return(true)
end
it 'returns regular content without survey URL' do
expect(presenter.outgoing_content).to eq('Rate your experience')
it 'returns content without survey URL (HTML for WebWidget)' do
expect(presenter.outgoing_content).to eq("<p>Rate your experience</p>\n")
end
end
@@ -36,18 +36,20 @@ RSpec.describe MessageContentPresenter do
allow(message.inbox).to receive(:web_widget?).and_return(false)
end
it 'returns I18n default message when no CSAT config and dynamically generates survey URL' do
it 'returns I18n default message when no CSAT config and dynamically generates survey URL (HTML format)' do
with_modified_env 'FRONTEND_URL' => 'https://app.chatwoot.com' do
expected_url = "https://app.chatwoot.com/survey/responses/#{conversation.uuid}"
expect(presenter.outgoing_content).to include(expected_url)
expect(presenter.outgoing_content).to include('<p>')
end
end
it 'returns CSAT config message when config exists and dynamically generates survey URL' do
it 'returns CSAT config message when config exists and dynamically generates survey URL (HTML format)' do
with_modified_env 'FRONTEND_URL' => 'https://app.chatwoot.com' do
allow(message.inbox).to receive(:csat_config).and_return({ 'message' => 'Custom CSAT message' })
expected_url = "https://app.chatwoot.com/survey/responses/#{conversation.uuid}"
expect(presenter.outgoing_content).to eq("Custom CSAT message #{expected_url}")
expected_content = "<p>Custom CSAT message #{expected_url}</p>\n"
expect(presenter.outgoing_content).to eq(expected_content)
end
end
end