* feat(whatsapp): show contact typing and recording indicators via baileys presence
Subscribe to WhatsApp presence updates via the baileys-api provider to
display real-time typing and recording indicators in the dashboard.
- Handle presence.update webhook events (composing, recording, paused,
available) and broadcast via ActionCable
- Add conversation.recording event to ActionCable, webhook, and channel
listeners for parity with typing_on/typing_off
- Show "typing..." / "recording..." in green text on the chat list,
replacing the message preview
- Show "X is typing" / "X is recording audio" in the conversation view
- Add presence_subscribe provider config option (default off) to gate
all subscription calls to the baileys-api
- Subscribe to presence on conversation open and periodically (1 min)
for the top 10 chat list conversations
- Consolidate contact LID from presence.update jidAlt payload
- Prevent echo-back of contact typing events to the channel
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address review feedback
- Filter chat list typing indicator to contact-only events
- Add dedupe to presence subscribe bulk calls
- Use strong parameters for conversation_ids
- Remove redundant YAML quotes in swagger webhook enum
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address review feedback
- Extract phone from data[:id] when JID is @s.whatsapp.net (fallback
when jidAlt is absent)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address review feedback
- Filter recording users in getTypingUsersText to show correct names
- Add 10s timeout to presence_subscribe HTTP request
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: scope typing timer per user instead of per conversation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: make presence subscribe best-effort with rescue per channel
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address review feedback
- Add messagePreviewClass to typing preview for consistent padding
- Fix specs to use WebMock assertions instead of instance spying
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
# Pull Request Template
## Description
This PR fixes an issue where typing variables, like `{{contact.name}}`,
caused the variable list to miss showing `contact.name`. The search key
in this case became `contact.name}},` which didn't match any available
options. The logic in `VariableList.vue` only checked the part after the
last comma and didn’t fully sanitize the input.
**Solution**
Updated `searchKey` to remove all {} and commas for accurate matching.
Fixes
[CW-4574](https://linear.app/chatwoot/issue/CW-4574/i-dont-see-an-option-for-contactname-it-shows-initially-but-it-doesnt)
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
### Loom video
https://www.loom.com/share/fc86e53853ad49e6acf6de57ebbd8fcb?sid=6702f896-d1a3-4c5a-9eb7-b96b5ed91531
## 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
- [ ] 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
This fix consists of translating the message when another user is typing on the other side.
---
Co-authored-by: Pranav <pranavrajs@gmail.com>
Co-authored-by: Pranav <pranav@chatwoot.com>