- Fix ordered lists being sent as unordered lists in WhatsApp
integrations
- The WhatsApp markdown renderer was converting all lists to bullet
points (-), ignoring numbered list formatting
- Added ordered list support by tracking list_type and list_item_number
from CommonMarker AST metadata
Before:
Input: "1. First\n2. Second\n3. Third"
Output: "- First\n- Second\n- Third"
After:
Input: "1. First\n2. Second\n3. Third"
Output: "1. First\n2. Second\n3. Third"
Problem: SystemStackError: stack level too deep occurred when rendering
messages with indented content (4+ spaces) for WhatsApp, Instagram, and
Facebook channels.
Root Cause: CommonMarker::Renderer#code_block contains a self-recursive
placeholder that must be overridden:
```
def code_block(node)
code_block(node) # calls itself infinitely
end
```
WhatsAppRenderer and InstagramRenderer were missing this override,
causing infinite recursion when markdown with 4-space indentation
(interpreted as code blocks) was rendered.
Fix: Added code_block method to both renderers that outputs the node
content as plain text:
```
def code_block(node)
out(node.string_content)
end
```
Fix https://linear.app/chatwoot/issue/CW-6217/systemstackerror-stack-level-too-deep-systemstackerror
## Summary
Fixes the issue where double newlines (paragraph breaks) were collapsing
to single newlines in text-based messaging channels (Telegram, WhatsApp,
Instagram, Facebook, LINE, SMS).
### Root Cause
The `preserve_multiple_newlines` method only preserved 3+ consecutive
newlines using the regex `/\n{3,}/`. When users pressed Enter twice
(creating a paragraph break with 2 newlines), CommonMarker would parse
this as separate paragraphs, which then collapsed to a single newline in
the output.
This caused:
- ❌ Normal Enter: Double newlines collapsed to single newline
- ✅ Shift+Enter: Worked (created hard breaks)
### Fix
Changed the regex from `/\n{3,}/` to `/\n{2,}/` to preserve 2+
consecutive newlines. This prevents CommonMarker from collapsing
paragraph breaks.
Now:
- ✅ Single newline (`\n`) → Single newline (handled by softbreak)
- ✅ Double newline (`\n\n`) → Double newline (preserved with
placeholders)
- ✅ Triple+ newlines → Preserved as before
### Test Coverage
Added comprehensive tests for:
- Single newlines preservation
- Double newlines (paragraph breaks) preservation
- Multiple consecutive newlines
- Newlines with varying amounts of whitespace between them (1 space, 3
spaces, 5 spaces, tabs)
All 66 tests passing.
### Impact
This fix affects all text-based messaging channels that use the markdown
renderer:
- Telegram
- WhatsApp
- Instagram
- Facebook
- LINE
- SMS
- Twilio SMS (when configured for WhatsApp)
Fixes
https://linear.app/chatwoot/issue/CW-6135/double-newline-is-breaking
---------
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
## Description
Fixes an issue where multiple newlines with whitespace between them
(e.g., `\n \n \n`) were being collapsed to single newlines in text-based
messaging channels (Telegram, WhatsApp, Instagram, Facebook, Line, SMS).
The frontend was sending messages with spaces/tabs between newlines, and
the markdown renderer was treating these as paragraph content,
collapsing them during rendering.
### Changes:
1. Added whitespace normalization in `render_telegram_html`,
`render_whatsapp`, `render_instagram`, `render_line`, and
`render_plain_text` methods
2. Strips whitespace from whitespace-only lines before markdown
processing
3. Added comprehensive regression tests for all affected channels
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
1. **Unit Tests**: Added 7 new specs testing multiple newlines with
whitespace between them for all text-based channels
2. **Manual Testing**: Verified with actual frontend payload containing
`\n \n \n` patterns
3. **Regression Testing**: All existing 63 specs pass
### Test Results:
- ✅ All 63 markdown renderer specs pass (56 original + 7 new)
- ✅ All 12 Telegram channel specs pass
- ✅ All 27 WhatsApp + Instagram specs pass
- ✅ Verified with real-world payload: 18 newlines preserved (previously
collapsed to 1)
### Test Command:
```bash
RAILS_ENV=test bundle exec rspec spec/services/messages/markdown_renderer_service_spec.rb
RAILS_ENV=test bundle exec rspec spec/models/channel/telegram_spec.rb
```
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective
- [x] New and existing unit tests pass locally with my changes
## Description
This PR fixes an issue where multiple consecutive newlines (blank lines
for visual spacing) were being collapsed in text-based messaging
channels like WhatsApp, Instagram, and SMS.
When users send messages via API with intentional spacing using multiple
newlines (e.g., `\n\n\n\n`), the markdown renderer was following
standard Markdown spec and collapsing them into single blank lines.
While this is correct for document formatting, messaging platforms like
WhatsApp and Instagram support and preserve multiple blank lines for
visual spacing.
The fix adds preprocessing to preserve multiple consecutive newlines
(3+) by converting them to placeholder tokens before CommonMarker
processing, then restoring the exact number of newlines in the final
output.
## Changes
- Added `preserve_multiple_newlines` and `restore_multiple_newlines`
helper methods to `MarkdownRendererService`
- Updated `render_whatsapp` to preserve multiple consecutive newlines
- Updated `render_instagram` to preserve multiple consecutive newlines
- Updated `render_plain_text` (affects SMS, Twilio SMS, Twitter) to
preserve multiple consecutive newlines
- Updated `render_line` to preserve multiple consecutive newlines
- HTML-based renderers (Email, Telegram, WebWidget) remain unchanged as
they handle spacing via HTML tags
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
- [ ] This change requires a documentation update
## How Has This Been Tested?
Added comprehensive test coverage:
- 3 new tests for multi-newline preservation across WhatsApp, Instagram,
and SMS channels
- All 56 tests passing (up from 53)
Testing scenarios:
- Single newlines preserved: `"Line 1\nLine 2"` remains `"Line 1\nLine
2"`
- Multiple newlines preserved: `"Para 1\n\n\n\nPara 2"` remains `"Para
1\n\n\n\nPara 2"`
- Standard paragraph breaks (2 newlines) work as before
- Markdown formatting (bold, italic, links) continues to work correctly
- Backward compatibility maintained for all channels
## 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
- [x] Any dependent changes have been merged and published in downstream
modules
## Description
This PR fixes an issue where Twilio WhatsApp messages were losing
newlines and markdown formatting. The problem had two root causes:
1. Text-based renderers (WhatsApp, Instagram, SMS) were converting
newlines to spaces when processing plain text without markdown list
markers
2. Twilio WhatsApp channels were incorrectly using the plain text
renderer instead of the WhatsApp renderer, stripping all markdown
formatting
The fix updates the markdown rendering system to:
- Preserve newlines by overriding the `softbreak` method in WhatsApp,
Instagram, and PlainText renderers
- Detect Twilio WhatsApp channels (via the `medium` field) and route
them to use the WhatsApp renderer
- Maintain backward compatibility with existing code
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
- [ ] This change requires a documentation update
## How Has This Been Tested?
Added comprehensive test coverage:
- 3 new tests for newline preservation in WhatsApp, Instagram, and SMS
channels
- 4 new tests for Twilio WhatsApp specific behavior (medium detection,
formatting preservation, backward compatibility)
- All 53 tests passing (up from 50)
Manual testing verified:
- Twilio WhatsApp messages with plain text preserve newlines
- Twilio WhatsApp messages with markdown preserve formatting (bold,
italic, links)
- Regular WhatsApp, Instagram, and SMS channels continue to work
correctly
- Backward compatibility maintained when channel parameter is not
provided
## 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
- [x] Any dependent changes have been merged and published in downstream
modules
# 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>
## Context
Sidekiq logs only showed the Sidekiq wrapper class and JID, which wasn’t
helpful when debugging ActiveJobs.
## Changes
- Updated `ChatwootDequeuedLogger` to log the actual `ActiveJob class`
and `job_id` instead of the generic Sidekiq wrapper and JID.
> Example
> ```
> Dequeued ActionMailer::MailDeliveryJob
123e4567-e89b-12d3-a456-426614174000 from default
> ```
- Remove sidekiq worker and unify everything to `ActiveJob`
Previously, email replies were handled inside workers. There was no
execution logs. This meant if emails silently failed (as reported by a
customer), we had no way to trace where the issue happened, the only
assumption was “no error = mail sent.”
By moving email handling into jobs, we now have proper execution logs
for each attempt. This makes it easier to debug delivery issues and
would have better visibility when investigating customer reports.
Fixes
https://linear.app/chatwoot/issue/CW-5538/emails-are-not-sentdelivered-to-the-contact
---------
Co-authored-by: Sojan Jose <sojan@pepalo.com>
Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
- Added an api endpoint for update message status ( available only for
api inboxes )
- Moved message status management to a service.
- Handles case where read status arrive before delivered
fixes: #10314 , #9962
This PR addresses an issue where mention_notification was being
overwritten by assigned_conversation_new_message notifications.
Similarly, participating_conversation_new_message was taking priority
over assigned_conversation_new_message.
The fix ensures that additional notifications are not created in these
scenarios by establishing a priority order for notifications as follows:
1. mention_notification
2. assigned_conversation_new_message
3. participating_conversation_new_message
This change maintains consistency and prevents redundant notifications.
----
Note: In the older implementation of notifications in Chatwoot,
notification objects were created only if the user had subscribed to a
specific notification type. With the new inbox_view model, we are
changing this approach to create notification objects in all cases. This
PR updates the services to remove reliance on notification preferences,
simplifying the logic.
----
Caveat: Since we don’t create extra notifications for new messages if a
mention_notification already exists, a user subscribed to
new_message_notification push/email notifications but not to
mention_notification will not receive notifications in these cases.