9cb045f46f
110 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
112385fd9e |
Merge branch 'main' into chore/merge-4.13.0
Resolves 26 conflicts via manual review. Key decisions: - signature: kept fork's send-time architecture (PR #79), discarded upstream's editor-manipulation functions - WhatsApp incoming: combined fork's two-layer locking (source_id + contact phone) with upstream's blocked-contact drop. Fixed pre-existing regression where echoes were silently dropped - InstallationConfig: upstream's simplified coder (validated against legacy YAML-in-jsonb data) - schema.rb: regenerated, stripped kanban tables from other branches, restored f_unaccent SQL function |
||
|
|
722e68eecb
|
fix: validate support_email format and handle parse errors in mailer (#13958)
## Description ConversationReplyMailer#parse_email calls Mail::Address.new(email_string).address without error handling. When an account's support_email contains a non-email string (e.g., "Smith Smith"), the mail gem raises Mail::Field::IncompleteParseError, crashing conversation transcript emails. This has caused 1,056 errors on Sentry (EXTERNAL-CHATINC-JX) since Feb 25, all from a single account that has a name stored in the support_email field instead of a valid email address. Closes https://linear.app/chatwoot/issue/CW-6687/mailfieldincompleteparseerror-mailaddresslist-can-not-parse-orsmith ## Type of change Please delete options that are not relevant. - [ ] Bug fix (non-breaking change which fixes an issue) ## Checklist: - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Vishnu Narayanan <iamwishnu@gmail.com> |
||
|
|
3aca86aa43
|
feat(internal-chat): implement internal chat system for agents (#247)
* feat(internal-chat): implement internal chat system for agents (Phase 1+2 MVP)
Add a Slack/Discord-style internal messaging system for Chatwoot agents with
text channels (public/private), direct messages, reactions, typing indicators,
and real-time updates via ActionCable.
Backend:
- 6 database migrations (categories, channels, members, messages, attachments, reactions)
- 6 models under InternalChat:: namespace with validations and associations
- API controllers for categories, channels, messages, members, and reactions
- Pundit policies for authorization (public/private/DM access control)
- MessageCreateService, TypingStatusManager, DefaultChannelSetupService
- InternalChatListener for real-time broadcasting to channel members
- Event types for internal chat events
- Default category/channel setup for new and existing accounts
Frontend:
- Vuex store modules for channels, messages, and typing status
- API clients for channels and messages
- Vue 3 components: InternalChatLayout, ChannelSidebar, ChannelView,
ChannelHeader, MessageList, MessageBubble, MessageEditor,
EmojiReactionPicker, ReactionDisplay, TypingIndicator
- Sidebar integration with "Internal Chat" menu item
- ActionCable handlers for real-time message/reaction/typing events
- Route definitions and i18n translations
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test(internal-chat): add comprehensive specs for models, controllers, policies, services, and listener
- 6 model specs (74 examples) covering associations, validations, scopes, methods
- 5 request specs for all API controllers (categories, channels, messages, members, reactions)
- 4 policy specs testing authorization rules for all actions
- 3 service specs (DefaultChannelSetupService, MessageCreateService, TypingStatusManager)
- 1 listener spec testing real-time broadcasting for all event types
- 6 FactoryBot factories with traits for all InternalChat models
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): fix dispatcher mock in service specs and cursor pagination test
- Allow dispatcher.dispatch in service specs to handle Account.created
callbacks from factory setup before asserting specific event dispatch
- Fix after-cursor pagination test by adding 1 second offset to avoid
timestamp precision issues with iso8601 rounding
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): address CodeRabbit review — 7 critical security/correctness fixes
- Scope member creation through Current.account.users to prevent cross-account membership
- Scope member_ids in DM creation through Current.account to prevent cross-account invites
- Scope reaction message lookup through channel account to prevent cross-account access
- Fix Vuex store to commit messages array instead of response envelope
- Add UUID generation callback on Channel model (before_validation)
- Add channel access check to reaction deletion policy
- Validate parent_id belongs to same channel in MessageCreateService
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): address CodeRabbit round 2 + fix ChannelSidebar runtime error
- Re-throw error in fetchMessages instead of swallowing with empty array
- Wrap message + attachment creation in transaction for atomicity
- Fix factory to derive account from message (prevent cross-account fixtures)
- Guard listener against cross-account mismatch (not just missing records)
- Add cross-account regression tests to listener spec
- Fix ChannelSidebar computed properties to default to empty arrays
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(internal-chat): auto-setup default channels on account creation and migration
- Add after_create_commit :setup_internal_chat callback on Account model
- Add data migration to create default channels for existing accounts
- Make DefaultChannelSetupService convergent (find_or_create) instead of
bail-on-exists, so it can sync new members on subsequent runs
- Fix specs to handle default category/channel created by callback
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): avoid Vuex state mutation in sort + align muted styling in fallback section
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): fix store module name mismatch — register as 'internalChat' not 'internalChatChannels'
Components dispatch to 'internalChat/get' but the module was registered
as 'internalChatChannels'. Also fix ActionCable handlers to use
'internalChat/messages/' nested module path.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* i18n(internal-chat): add pt-BR translations for internal chat feature
Backend: default_category_name ('Canais') and default_channel_name ('Geral')
Frontend: all 40+ keys translated to Brazilian Portuguese
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): handle ISO 8601 timestamps in MessageBubble and MessageList
The API returns created_at as ISO strings but messageTimestamp() expects
Unix seconds and MessageList used `* 1000`. Now handles both formats.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs(internal-chat): build swagger output for internal chat API endpoints
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs(internal-chat): register internal chat tags and paths in swagger index
Add tag definitions and path entries for all 5 internal chat resource
groups in swagger/index.yml and swagger/paths/index.yml. Rebuild output.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* i18n(internal-chat): add SIDEBAR.INTERNAL_CHAT key to pt-BR settings
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): comprehensive review fixes — backend and frontend
Backend:
- Add attachments to message API responses in both controllers
- Add internal_chat_channel_updated listener handler
- Include reactions in message event broadcast data
Frontend:
- Fix ActionCable dispatch paths to use correct action names
(addMessageFromCable, updateMessageFromCable, deleteMessageFromCable)
- Connect typingUsers to internalChatTypingStatus store getter
- Fix message field references (edited → content_attributes.edited_at)
- Fix channel type comparisons (use 'private_channel'/'dm' strings)
- Add parent 'internal_chat' to sidebar activeOn array
- Increment unread_count on ActionCable message receive
- Add loadMore handler for cursor-based pagination
- Remove unused is-direct-message prop from InternalChatLayout
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(internal-chat): implement phases 3-5 — threads, mentions, notifications, polls, drafts
Phase 3 — Threads, Mentions, Notifications:
- MentionService: parse @user mentions, @all (admin only), generate notifications
- NotificationService: create notifications for channel messages (respects mute)
- Add internal_chat_message/mention notification types to Notification model
- ThreadPanel.vue: slide-out panel for threaded replies
- Integrate mentions + notifications into MessageCreateService
Phase 4 — Polls:
- 3 new migrations: polls, poll_options, poll_votes tables
- 3 new models: Poll, PollOption, PollVote with validations
- PollsController: create poll, vote, unvote with routes
- PollService: voting logic with multiple choice + revote support
- PollCreator.vue: modal for creating polls with options
- PollDisplay.vue: vote UI with progress bars and results
- Polls Vuex store module
- INTERNAL_CHAT_POLL_VOTED event type
Phase 5 — Drafts:
- 1 new migration: drafts table
- Draft model with validations
- DraftsController: full CRUD (replace stub)
- DraftsList.vue: list all user drafts with navigation
- Drafts Vuex store module with auto-save
- Draft route and sidebar integration
Phase 6 — Feature Flag:
- Add INTERNAL_CHAT feature flag to features.yml and featureFlags.js
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): fix API routing for drafts and polls, add poll voting ActionCable handler
- Fix draft API client to use channel-scoped PATCH/DELETE endpoints
- Create dedicated polls API client with correct poll-based endpoints
- Update polls store to use InternalChatPollsAPI with pollId-based voting
- Add ActionCable handler for internal_chat.poll.voted events
- Add thread and drafts routes to sidebar activeOn array
- Fix drafts store to pass channelId to API calls
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): fix poll response format and API client routing (review round 2)
- Return message with embedded poll data instead of raw poll response
- Add poll data to message_response in messages controller
- Create dedicated InternalChatPollsAPI client with correct endpoints
- Update PollDisplay.vue to read from message.poll or content_attributes.poll
- Use option.voted flag instead of checking voters array
- Add missing PERCENTAGE i18n key to pt-BR
- Remove unused currentUserId prop from PollDisplay
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): fix poll voting and draft lookup bugs (review round 3)
- Fix draft getter to use internal_chat_channel_id field name
- Split poll set_poll into vote/unvote variants — unvote doesn't need option_id
- Unvote finds user's vote by user_id across all poll options
- Fix ChannelView to extract pollId from message.poll before dispatching
- Fix unvote handler to not require optionId
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 3)
- Expose is_dm, favorited, muted on channel API responses
- Normalize poll cable updates into message-shaped patch
- Add file presence validation to MessageAttachment
- Remove duplicate mention notifications from MentionService
- Make data migration rollback safe (IrreversibleMigration)
- Update factory to include file by default
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: return 201 for channel creation and optimize DM lookup
- Return :created (201) instead of :ok (200) for channel creation
- Replace O(n) Ruby scan with SQL-based DM lookup using ARRAY_AGG
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 5)
- Broadcast channel event after create for real-time notifications
- Separate create/update strong params to prevent channel_type transitions
- Use strong params for typing_status input
- Replace find_by with detect on preloaded collections to fix N+1
- Preload attachments with blobs in show response
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 6)
- Serialize DM creation with advisory lock to prevent duplicates
- Broadcast channel deletion event for real-time UI updates
- Use strong params for mark_unread message_id
- Batch unread count computation to eliminate N+1 in index
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: eliminate N+1 in compute_unread_counts with single JOIN query
Replace per-membership COUNT loop with a single JOIN + GROUP BY query
that returns all unread counts in one database call.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): quality fixes, missing tests, and Playwright E2E setup
Addresses quality issues found during review and fills test coverage gaps
for the internal chat feature.
Backend fixes:
- Return 201 for all create endpoints (messages, categories, polls, reactions, members)
- Fix N+1 queries: replies.size, poll votes, category channels.count, votes.exists?
- Fix pagination has_more logic to check page size instead of total count
- Scope poll vote/unvote to current account (security fix)
- Add internal_chat.messages.deleted i18n key
- Use find_by! in mark_unread for proper 404 on non-members
- Guard time param parsing with rescue ArgumentError
- Align message response format between channels and messages controllers
- Switch notification service to ActionCable-only (avoid push/email crashes)
Frontend fixes:
- Fix pinned message detection (content_attributes.pinned, not message.pinned)
- Fix thread reply count key (replies_count, not thread_replies_count)
- Fix markUnread to pass message_id parameter
- Fix pagination: PREPEND_MESSAGES mutation instead of overwriting
- Fix typing status to read Vuex reactive state, not stale closure
- Fix deleteDraft argument shape (pass { channelId, draftId })
- Fix DM channel filtering (check both is_dm and channel_type)
- Fix DraftsList navigation to use correct channel ID key
- Wire PollCreator to poll button in MessageEditor
- Wire settings event handler on ChannelHeader
- Reset PollCreator isSubmitting on timeout
New RSpec tests (67 examples):
- Factories: polls, poll_options, poll_votes, drafts
- Model specs: Poll, PollOption, PollVote, Draft
- Controller specs: PollsController, DraftsController
- Service specs: PollService, NotificationService, MentionService
Playwright E2E setup (37 tests):
- Install Playwright with Chromium
- Auth helper with Devise Token Auth login flow
- 8 test suites: navigation, channels, messaging, DMs, reactions, threads, polls, mark-read-unread
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 7)
Backend:
- Use lambda for UUID default in channels migration
- Wrap poll creation in transaction for atomicity
- Preload replies in thread action to avoid N+1
- Broadcast replies_count + attachments in listener (match REST shape)
- Scope draft listing through accessible channels
- Key draft upserts/deletes by parent_id for thread drafts
Frontend:
- Remove duplicate poll methods from internalChatMessages.js (use internalChatPolls.js)
- Persist toggleMute/toggleFavorite to backend via updateMember API
- Clear active channel on DELETE_CHANNEL mutation
- Skip unread increment for active channel in ActionCable handler
- Filter archived channels from sidebar getters
- Fix ChannelHeader isArchived to check status === 'archived'
- Prevent duplicate reactions in ADD_REACTION mutation
- Merge poll data into existing content_attributes on cable updates
- Guard infinite scroll against duplicate loads
- Add response.ok() check in E2E auth helper, remove hardcoded account ID
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 8)
- Remove unused nested typingStatus module from internalChat store
- Add parent_id to draft uniqueness scope and migration index
- Exclude reaction creator from reaction_created broadcast
- Preload attachments and poll associations in thread/messages queries
- Handle `after` fetches with APPEND_MESSAGES mutation
- Wrap channel creation payloads under `channel` key in E2E helpers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: rewrite Playwright E2E tests to use actual UI interactions
Completely rewrote all 8 E2E test suites to work with the live app:
- Test through actual UI interactions, not API bypass
- Use correct Portuguese (pt_BR) locale strings
- Use structural selectors matching real Vue component DOM
- Dynamic account ID from login response (no hardcoded values)
- 3 parallel workers, increased timeouts for reliability
- API calls only for preconditions (seeding test data)
29 tests passing across navigation, channels, messaging, DMs,
reactions, threads, polls, and mark-read-unread suites.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use partial unique indexes for draft uniqueness with NULL parent_id
PostgreSQL treats NULL as distinct in unique constraints, so a composite
index on (user_id, channel_id, parent_id) allows duplicate root drafts.
Split into two partial indexes: one for root drafts (WHERE parent_id IS
NULL) and one for thread drafts (WHERE parent_id IS NOT NULL).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 9)
- Remove duplicate index on internal_chat_polls.internal_chat_message_id
(keep only unique index)
- Add options validation in polls create (return 400 instead of 500)
- Add expiration check to unvote action (match vote behavior)
- Use strong params in messages update action
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 10)
- Change channel associations from destroy_async to destroy (FK
constraints are ON DELETE RESTRICT, blocking async deletion)
- Remove unused internal_chat notification types and PRIMARY_ACTORS
entry (notification service uses ActionCable only, no DB records)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 11)
- Scope category_id to current account in channels controller (security)
- Defer message-created event in poll creation until after transaction
- Change message associations from destroy_async to destroy (FK compat)
- Validate option belongs to poll in poll_service
- Use strong params for emoji in reactions controller
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 12)
Backend (9 fixes):
- Gate message update/destroy by channel accessibility in policy
- Guard content_attributes nil before merge in polls controller
- Fix after-cursor pagination to use limit() instead of last()
- Wrap revote in transaction for atomicity in poll service
- Make unvote option-specific for multi-choice polls
- Exclude own messages from unread count
- Make channel activity update monotonic (only write if newer)
- Include actor in message/reaction broadcasts (multi-tab support)
- Return 400 for empty member create instead of 201
Frontend (8 fixes):
- Show uncategorized channels even when categories exist
- Clear editor on channel switch when no draft exists
- Soft-delete messages in store (update in place, don't remove)
- Guard ThreadPanel against out-of-order fetch responses
- Replace hardcoded channel label with i18n key in DraftsList
- Add accessible name to settings button in ChannelHeader
- Add aria-label to search field in ChannelSidebar
- Make MessageBubble actions keyboard-accessible via focus-within
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 13)
- Fix keyword argument mismatch in reactions dispatch_reaction_event
- Add user_id to reaction cable broadcast for shape consistency with REST
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): quality fixes, expanded RSpec + Playwright E2E tests
Fix isArchived computed (checked .archived instead of .status), fix
ReactionDisplay user identification (.user?.id vs .user_id), update
17 spec assertions from :success to :created on create endpoints,
add 32 new RSpec examples (polls, drafts, services), and rewrite
8 Playwright E2E test files with correct selectors, proper test
isolation, and dynamic user ID discovery.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 14)
Prevent duplicate votes on same option in multi-choice polls with
explicit BadRequest guard. Add internal_chat webhook events to
ALLOWED_WEBHOOK_EVENTS so users can subscribe to them.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: include poll data in ActionCable broadcast for poll messages
Extract base_message_data helper and enrich message_event_data with
poll options when the message has an associated poll, ensuring
realtime subscribers receive the same poll data as REST API clients.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 15)
Backend: wrap single-choice revotes in transaction, capture member
tokens before channel destroy, exclude own messages from unread count,
strip attachments from deleted messages, enrich poll broadcast payload.
Frontend: use getCurrentRole getter, fix public-results poll display,
sync thread replies via store, add close button a11y, pass option_id
to unvote API, pass parent_id to deleteDraft API.
Models: handle nil last_read_at for new members, skip content
validation for attachment-only messages, align PollService guards
with controller, change category dependent to nullify.
Swagger: add attachments to message schema, fix create status to 201.
E2E: remove fragile waitForTimeout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): fix 21 UX/functional issues
Address 21 UX gaps discovered during product testing:
Sidebar & Navigation:
- Fix search icon overlap, extend search to description + DM members
- Add create channel/DM/category buttons and modals
- Show DM member names instead of null
- Include members data in channel index API for DMs
Message Interactions:
- Add delete confirmation dialog
- Implement inline message editing with cancel support
- Toggle emoji reactions (add/remove)
- Support multiple pinned messages with click-to-scroll
- Prevent thread replies from appearing in main chat
- Fix reply count live updates
- Hide pin button on thread messages
- Improve deleted message styling with greyed-out card
- Replace spinner with skeleton loading
- Add markdown toolbar (bold/italic/code)
- Fix thread editing and add vote/unvote handlers
Features & Polish:
- Implement channel settings slide-over panel
- Fix thread loading not affecting main channel spinner
- Fix poll creation field name mismatch with backend API
- Fix drafts: show channel names, handle DM navigation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): use Dialog modal for delete confirmation
Replace window.confirm with the project's Dialog component for
message delete confirmation, providing a consistent UI experience.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 16)
- Require content field in message update OpenAPI schema
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 17)
- Sanitize advisory lock SQL with sanitize_sql_array
- Use semantic button for pinned message banner
- Add aria-label to ChannelSettings close button
- Add type="button" to all ChannelSettings buttons
- Gate channel/DM/category creation to admins
- Replace hardcoded 'Direct Message' with i18n key
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 18)
- Wrap DM creation payload in channel key for consistency
- Replace raw text in category select with i18n key
- Add IME composition guard to prevent premature send
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(internal-chat): UX round 2, rich editor, team members, drag-and-drop
- Reduce sidebar spacing between search bar and drafts
- Fix search icon overlapping placeholder text
- Replace inline category form with Dialog modal
- Add collapsible sidebar sections with localStorage persistence
- Add drag-and-drop channels across categories (admin-only, vuedraggable)
- Replace textarea editor with WootWriter ProseMirror rich text editor
- Replace regex markdown rendering with shared MessageFormatter
- Wire draft auto-save pipeline with WootWriter (3s debounce watcher)
- Add team + agent selection when creating private channels
- Auto-add all agents when creating public channels
- Sync team members to linked channels via TeamMember callback
- Fix member list not loading on first settings panel open
- Complete PT-BR translations for all internal chat strings
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(internal-chat): UX round 3, Enter-to-send, mentions, copy link, poll modal
- Send with Enter (not Cmd+Enter), Shift+Enter for newlines
- Enable @mentions via WootWriter suggestions plugin
- Refocus editor after sending a message
- Copy link to message button in hover toolbar
- Poll creator refactored to Dialog with confirm-discard on close
- Channel type uses Switch instead of dropdown
- Category uses components-next Select instead of native select
- Skeleton loading: only on initial load, spinner for pagination
- Scroll position preserved when loading older messages
- Mute/Favorite buttons fixed (store members updated after fetch)
- Add/remove channel members after creation (admin-only)
- Save draft immediately when switching channels
- Settings sidebar remembers open/closed state via localStorage
- Search icon overlap fixed (increased padding)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): DM settings, copy updates, input refocus, member UX
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): member edit for private only, emoji overflow, reaction tooltips
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): thread count sync, scroll loading, copy link, thread/settings exclusivity
- Fix thread reply count doubling (remove duplicate INCREMENT_REPLY_COUNT from sendThreadReply, cable handles it)
- Fix copy link button (use window.location.origin + pathname as fallback)
- Hide poll button in thread editor
- Add "Also send in #channel" checkbox for thread replies
- Increase scroll threshold for loading older messages (100px instead of 0)
- Track and stop loading when oldest message reached
- Thread and settings panels are mutually exclusive
- Refocus editor after send with delayed focus
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): scroll to linked message via ?messageId= query param
Read messageId from route query on mount, scroll to and highlight the
target message after messages load, then clean the query param.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): prevent editor from becoming unfocusable after send
Root cause: passing disabled prop to WootWriter applies pointer-events-none
and ProseMirror does not re-enable contenteditable when disabled returns to
false. Fix: never disable the WootWriter, use a local isSending guard to
prevent double-sends. Refocus 300ms after send for ProseMirror state reload.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): simplify send guard, no artificial timeout
Content is cleared immediately before emit, so canSend naturally
returns false (empty content). No isSending guard needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): align poll option remove buttons vertically
Increase padding to p-1.5 and add flex-shrink-0 for consistent sizing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): close poll modal after creating poll
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): poll option X button alignment, discard modal on submit
- Button uses explicit 34px height matching input, no items-center
- Reset form before closing dialog so hasUnsavedChanges is false
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): close settings sidebar when clicking reply
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): update poll UI after voting, fix re-vote error
Vote/unvote actions now dispatch updateMessageFromCable with the API
response to update poll state locally. Pass channelId to enable this.
Clicking an already-voted option correctly triggers unvote.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): include poll data in message response, add timer and voters
Backend: message_response now includes poll data (options, votes, voted
status, voters for public polls) via eager-loaded poll association.
This fixes polls not rendering after page reload.
Frontend PollDisplay:
- Countdown timer showing time remaining until poll closes
- Read-only state when expired (div instead of button, no hover)
- Voter names shown below each option (public polls or admin)
- Prefer content_attributes.poll over message.poll for fresh data
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): include channel_id in poll voted cable broadcast
The poll_event_data was missing internal_chat_channel_id, so the
frontend cable handler could not route the update to the correct
channel's message store.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): poll vote highlight, typing off, reaction broadcast, translations
- Preserve per-user voted flags when merging cable poll broadcast
- Send typing_off after 3s of no typing activity
- Include internal_chat_channel_id in reaction event broadcasts
- Fix reaction deleted handler to also check channel_id field
- Simplify "also send in" copy (works for both channels and DMs)
- Add PT-BR translation for ALSO_SEND_IN_CHANNEL
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(internal-chat): unified reaction popover with all emoji groups
Clicking any reaction badge opens a single popover showing all reactions
grouped by emoji with user names. Current user can remove their own
reaction via X button. Replaces per-reaction popover with unified view.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): wire close DM button to archive and navigate home
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(internal-chat): close DM via hidden flag on channel membership
Add hidden boolean to channel_members table. Close DM sets hidden=true
via member update API. Sidebar filters out hidden DMs. New messages on
a DM channel automatically unhide all members via listener callback.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): reaction popover, user names, file upload support
- Include user name in reaction API response (was missing)
- Redesign reaction popover: flat list with emoji + name per row,
aligned X button for removing own reactions
- Add file upload: paperclip button opens file picker, attached files
shown as chips with remove, sent via FormData with message
- Store action and API client support files parameter
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): reaction user names, unreact button, attachment rendering
- Include user name in reactions across all endpoints (messages_controller,
listener base_message_data)
- Make unreact X button always visible (bg-n-alpha-2 background)
- Render message attachments as downloadable links with paperclip icon
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(internal-chat): image preview for attachments in messages and editor
Messages: images render inline with max-h-60, non-images as download links.
Editor: image files show thumbnail preview, non-images show file icon + name.
Remove button as floating circle on top-right corner of each attachment.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): attachment preview matches conversation pattern
- File previews show name + size (e.g. "2 MB") in a horizontal card
- Image thumbnails as 32px squares, non-images show document emoji
- Remove button is a visible X icon (not a floating circle)
- Layout matches AttachmentsPreview from conversation ReplyBox
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): auto-detect image file type from MIME on upload
MessageCreateService now detects file type from content_type instead of
defaulting to :file. Images are correctly tagged as :image so they
render inline in message bubbles.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): include file_url in cable broadcast, fix filename display
Listener attachment_event_data now includes file_url so attachments
render correctly on real-time messages without page refresh.
MessageBubble extracts filename from URL or falls back to file_type+ext.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): pin attachments, edit members modal, settings persistence
- Skip content validation when pinning/unpinning (fixes pin on file-only messages)
- Add EditMembersModal with search, add, and remove members for private channels
- Fix settings sidebar always opening: @close now calls handleToggleSettings
which updates localStorage, not just sets ref to false
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): fix X buttons for attachment remove and reaction unreact
Replace Icon component with inline SVG cross for reliable rendering.
Both attachment remove and reaction unreact buttons now show a visible
X icon at all times with proper vertical alignment.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): allow any user to pin messages, not just sender/admin
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): restore Icon component for X buttons (size-4 in size-6 container)
SVG inline approach didn't render. Reverted to Icon i-lucide-x with
larger sizes (size-4 icon in size-6 button) which renders reliably.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): use p-1 + size-4 pattern for X buttons (matches message toolbar)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(internal-chat): thread indicator on messages from threads, allow pinning all
- Show "Thread" badge with icon on messages that have parent_id,
clicking it opens the parent thread
- Remove parent_id restriction from canPin, any non-deleted message
can be pinned
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): thread indicator, poll close loop, thread navigation
- Hide thread indicator inside thread panel (inThread prop)
- Open parent thread when clicking thread badge on messages with parent_id
- Fix PollCreator infinite close loop (handleClose no longer calls
dialogRef.close, since Dialog already triggered the close)
- Look up parent message in store when opening thread from indicator
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(internal-chat): poll duration translations and clickable switch labels
- Duration options use i18n keys (EN + PT-BR: 24 horas, 7 dias, etc.)
- Multiple choice and Public results switches toggle by clicking label
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(internal_chat): enhance message handling and search functionality
- Added broadcasting of typing off events in InternalChatListener.
- Included member user IDs in channel data for better context.
- Updated message model to allow optional sender association.
- Implemented team mention expansion in MentionService to include team members.
- Enhanced message creation service to store mentioned user IDs in content attributes.
- Introduced a new SearchService for searching channels, DMs, and messages.
- Updated API responses to include has_unread_mention flag for channels.
- Added tests for user deletion behavior in internal chat, ensuring message preservation and reaction handling.
- Improved draft model to allow coexistence of root and thread drafts.
- Added unique indexes for drafts to prevent duplicate entries.
- Implemented foreign key constraints with appropriate delete behaviors for internal chat models.
* feat(internal-chat): swagger docs, webhook events, search UX improvements
Add Swagger documentation for drafts, polls, and search endpoints.
Wire internal_chat_message_deleted and internal_chat_channel_updated
webhook events to the UI and listener. Improve search empty state with
min-chars hint and friendly no-results message. Update CLAUDE.md to
include pt_BR translations.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(internal-chat): add draft count display in channel sidebar
* chore: remove playwright config and dependencies
* feat(internal-chat): polish UX, swagger updates, and migration consolidation
- Editor toolbar shortcuts (@ and #) with instant popover trigger,
including accent-insensitive matching and wider conversation popover
- Localized last activity time and inbox name on conversation preview cards
- Thread + main interplay: also-send-in-channel mirror, parent_id filter,
per-message conversation link, hidden buttons inside thread view,
reactions update across both lists, scroll-to-message behavior
- Search service uses f_unaccent for messages, channel names and user names
via dedicated GIN trigram functional indexes
- Renamed InternalChat::ProGating to InternalChat::Limits with neutral
semantics
- Consolidated 17 internal chat migrations into 3 (tables, default channels,
unaccent search) and added a rake task to ensure the f_unaccent function
exists before db:schema:load
- Swagger paths and definitions updated to match the current state of the
feature (also_send_in_channel, status codes, pro-required responses,
hidden member flag, search meta fields, etc.)
* fix(internal-chat): use Rake task augmentation for db:schema:load hook
The previous `Rake::Task['db:schema:load'].enhance(...)` guarded by
`task_defined?` silently no-op'd in CI when the rake file loaded before
ActiveRecord's rake_tasks block ran. Re-opening `db:schema:load` via
Rake's `task name => deps` DSL augments the existing task regardless of
load order, ensuring the f_unaccent function is created before schema.rb
references it.
* fix(internal-chat): enhance db:schema:load from Rakefile after load_tasks
Adding the prereq inside lib/tasks/internal_chat_search.rake (via either
`Rake::Task#enhance` or task DSL augmentation) was being silently dropped
in CI, presumably due to load order between application rake files and
ActiveRecord's `rake_tasks` block. Moving the `enhance` to the Rakefile
itself, after `Rails.application.load_tasks`, guarantees both
`db:schema:load` and `db:internal_chat:ensure_search_functions` are
defined before the prereq is added.
Also leaves a debug `puts` in the task body so future regressions are
visible from CI logs.
* chore(internal-chat): add diagnostic logging to f_unaccent hook
* fix(internal-chat): install f_unaccent on all envs iterated by db:schema:load
Rails' `db:schema:load` in development env iterates over BOTH the
development and test databases (see
`ActiveRecord::Tasks::DatabaseTasks.each_current_environment`), but our
hook was only installing the function on the currently-connected
database. CI defaults to development env (no `RAILS_ENV` set), so the
function landed on `chatwoot_dev` while `chatwoot_test` remained
without it, causing the schema load to fail when creating the functional
indexes against the test DB.
The hook now mirrors the same iteration logic and installs the function
on every relevant config, restoring the original AR connection
afterwards.
* fix(internal-chat): align listener spec with current broadcast payload
- internal_chat_message_created now emits two broadcasts (the message
itself plus an automatic typing_off), so the spec switches to
`allow`/`have_received` to assert the message broadcast without caring
about the additional typing_off call.
- internal_chat_reaction_created payload uses `message_id`, not
`internal_chat_message_id`. Update the spec expectation to match.
* chore(internal-chat): remove redundant DSL augmentation in rake task
* fix(internal-chat): harden gates, kill N+1s and reduce race risk
Closes review findings raised on the internal chat PR:
- Restrict role mass-assignment in ChannelMembersController so only
account administrators can promote new members to channel admin.
- Wrap private-channel create/unarchive in a Postgres advisory lock per
account so concurrent requests can no longer bypass the freemium limit.
- Replace `replies.size` and `votes.size` (per-broadcast queries) with
`replies_count` / `votes_count` counter caches.
- Make `update_channel_activity` an atomic compare-and-set update so
concurrent message creates can never regress `last_activity_at`.
- Optimize `Poll#total_votes_count` to use the cached column and eager-
loaded options instead of a per-poll `votes.count` query.
- Add `internal_chat_messages.account_id` foreign key (`ON DELETE
CASCADE`) to prevent orphan rows.
- Escape HTML in `ChannelSidebar.highlightMatch` to close a v-html XSS
via incomplete tags in message search snippets.
- Cleanup `typingOffTimer` on `ChannelView` unmount.
- Add stable sort to `getChannelsByCategory` (alphabetical) and
`getDMChannels` (last activity) to prevent UI reorder thrash.
- Localize `PollDisplay` time-remaining strings (en + pt-BR).
- Add specs covering the 90-day search history filter and the search
controller endpoint, plus regenerate the consolidated migration
with the new columns and FK.
* docs(swagger): note role mass-assignment restriction on channel members
Document that the `role` field on the channel member create payload is
silently coerced to `member` for callers that are not account
administrators, matching the controller behavior introduced in the
previous commit.
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
||
|
|
8fcef79847 | Merge branch 'chatwoot/develop' into chore/merge-upstream-4.12.0 | ||
|
|
c6bfd1eed3
|
feat: schedule messages recurrence (#240)
* feat(scheduled-messages): add recurring scheduled messages Implements the recurring scheduled messages feature allowing agents to configure recurrence rules when scheduling messages, with automatic creation of subsequent scheduled messages after each send. Backend: - RecurringScheduledMessage model with JSONB recurrence_rule validation - RecurrenceCalculatorService for next occurrence date calculation - RecurrenceDescriptionService for human-readable rule descriptions - CreateNextOccurrenceService for auto-creating child ScheduledMessages - RecurringScheduledMessagesController with CRUD operations - RecurringScheduledMessagePolicy for authorization - Modified SendScheduledMessageJob to handle recurrence after send - Updated due_for_sending scope to exclude resolved conversations - ActionCable events for real-time updates - Activity message i18n (en + pt-BR) Frontend: - RecurrenceDropdown.vue with contextual shortcut options - RecurrenceCustomModal.vue for custom recurrence configuration - RecurringScheduledMessageItem.vue for sidebar display - Integration into ScheduledMessageModal.vue - Updated ScheduledMessages.vue with recurrence section and filtering - Vuex store module for recurring scheduled messages - API client for CRUD operations - WebSocket handlers in actionCable.js - recurrenceHelpers.js utility functions - i18n keys for en and pt-BR Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): fix creation and edit visibility - Fix API payload key mismatch (snake_case vs camelCase) in modal submit - Add status: 'active' to recurring creation payload - Fix strong params to permit recurrence_rule array fields (week_days) - Cast string values from strong params to integers for JSONB validation - Show RecurrenceDropdown when editing (remove isEditing gate) - Populate recurrenceRule from scheduled message's recurring parent - Include recurring_scheduled_message_id and recurrence_rule in scheduled message jbuilder response Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): fix dropdown toggle and locale tag errors - Use DropdownItem :click prop instead of @click to use the injected closeMenu from DropdownContainer context (default slot doesn't expose toggle) - Normalize locale from pt_BR to pt-BR for Intl.DateTimeFormat compatibility in RecurringScheduledMessageItem Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(recurring-messages): add separator line and expandable history - Add border separator between recurring messages section and pending/draft messages, matching the history section separator - Replace static 'N enviadas' counter with clickable toggle that expands to show individual sent/failed child messages with status badges and formatted timestamps Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(recurring-messages): add click-to-navigate on sent children Make sent child messages in recurring message history clickable. Clicking navigates to the actual message in the conversation using the messageId query param, same pattern as ScheduledMessageItem. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(recurring-messages): allow editing recurring messages - Add edit button to RecurringScheduledMessageItem (active only) - Transform recurring message into scheduledMessage-compatible shape with recurring_scheduled_message_id set, so the modal reuses the existing update path - Handle edge case of removing recurrence from a recurring message (cancels series without trying to update a non-existent standalone) - Sent history is preserved by the backend update action Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): show recurrence field without date selection Remove v-if="scheduledDate" gate so the recurrence dropdown is always visible in the modal. Falls back to today's date for contextual shortcut labels when no date is selected yet. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): ensure recurrence visible on edit and add pending_scheduled_message to API - Add pending_scheduled_message to recurring_scheduled_message jbuilder so REST API data matches WebSocket push_event_data - Add fallback in openEditRecurringModal to find pending child from scheduled_messages array when pending_scheduled_message is absent - Add same fallback in nextSendLabel computed Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(scheduled-messages): add sections for Drafts and Pending messages in the UI * refactor(scheduled-messages): merge RecurringScheduledMessageItem into ScheduledMessageItem Consolidate the recurring message card into the existing ScheduledMessageItem component instead of maintaining a separate component. The unified component detects recurring messages via recurrence_rule and conditionally shows: - Recurrence description header with repeat icon - Next send time label - Expandable sent/failed children history with click-to-navigate - Stop button (replaces delete) with confirmation modal - Active/completed/cancelled status badges Delete the now-unused RecurringScheduledMessageItem.vue. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(scheduled-messages): use blue badge for active, keep green for sent Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(scheduled-messages): remove draft and pending sections from UI and update recurrence title * fix(recurring-messages): use Teleport for recurrence dropdown Replace DropdownContainer with Teleport-based floating dropdown so options render outside the modal. Fixes: - Dropdown no longer enlarges the modal or causes scrolling - Dropdown closes before Custom modal opens (no overlap) - Auto-detects available space and opens above/below trigger Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): recalculate next date when recurrence rule changes When editing a recurring message and changing the recurrence rule, the pending occurrence date is now validated against the new rule. If the user-provided date doesn't match (e.g. Thursday removed from weekly days), the system computes the next valid date using RecurrenceCalculatorService instead of blindly using the old date. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(scheduled-messages): resolve deprecated onClose and disabled type warnings - Replace :on-close prop with @close event on woot-modal components - Cast hasTemplate computed to boolean to fix disabled prop type check Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(scheduled-messages): replace remaining deprecated on-close props - ScheduledMessages.vue delete confirm modal - RecurrenceCustomModal.vue modal Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): address review feedback on PR #240 - Fix v-if/v-else bug hiding message list behind resolved warning - Fix occurrences_sent incrementing on failed sends (skip_increment flag) - Fix compute_next_valid_date using .min instead of .max - Fix Vuex delete action to update state on cancel (not remove) - Use atomic update_counters for occurrences_sent increment - Add safe Date.iso8601 parsing with rescue in should_complete? - Add null: false to occurrences_sent migration column - Fix pt-BR accent: Recorrencia → Recorrências - Use I18n.with_locale(account.locale) for all activity messages - Fix N+1 in jbuilder partials (Ruby filtering + eager loading) - Add interval >= 1 validation to RecurrenceCustomModal isValid - Validate recurrence_rule presence when status is active - Add ISO8601 date format validation for end_date - Add unknown_agent i18n key for fallback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): wrap create/update in transactions, clean pending on deactivation - Wrap create and update flows in ActiveRecord transactions - Move attachment purge after save! to prevent data loss on validation failure - Destroy pending children when status transitions to non-active - Fixes critical bug where stopping recurrence could leave armed pending messages Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): prevent monthly/yearly day-of-month drift Store the original intended day in recurrence_rule JSONB as month_day (for monthly) and year_day/year_month (for yearly). The calculator now uses these stored values instead of @last_date.day, preventing drift after short months cap the day (e.g., Jan 31 → Feb 28 → all subsequent months stuck on 28). Backend: - RecurrenceCalculatorService: use rule[:month_day] for monthly and rule[:year_day]/rule[:year_month] for yearly calculations - Controller: permit and cast the new integer keys Frontend: - recurrenceHelpers: yearly shortcuts include year_day/year_month - RecurrenceCustomModal: emit month_day for monthly day_of_month rules and year_day/year_month for yearly rules Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): i18n description services, align due_for_sending scope Backend: - RecurrenceDescriptionService: replace hardcoded English with I18n.t() calls; accept locale parameter and use I18n.with_locale - RecurringScheduledMessage model: pass account locale to description service - ScheduledMessage: align due_for_sending? instance method with scope by checking conversation status (open/pending) Frontend: - buildRecurrenceDescription: use t() i18n function instead of manual isPt locale branching - Add DESCRIPTION i18n keys to en/conversation.json and pt_BR/conversation.json - Update RecurrenceDropdown and ScheduledMessageItem callers to pass t i18n: - Add recurring_scheduled_messages.description.* keys to en.yml and pt_BR.yml Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): keep pending child when deactivating recurrence When editing a recurring message to disable recurrence while setting a future send date, the pending child message is now preserved instead of being destroyed. This allows a 'final send' without creating new recurrences (the send job already guards with recurring&.active?). Backend: - Add update_pending_on_deactivation: updates pending child's scheduled_at or creates a final pending occurrence - Replace destroy_all in update's non-active branch Frontend: - activeRecurringMessages now includes non-active recurring messages that still have a pending child (pending_scheduled_message) - Stop button hidden for already-cancelled recurring messages - inactiveRecurringMessages excludes messages with pending children Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): prevent removing recurrence from existing recurring message Once a scheduled message has recurrence, the 'Does not repeat' option is hidden from the RecurrenceDropdown when editing. This avoids edge cases where deactivating recurrence leaves the message in an ambiguous display state. - RecurrenceDropdown: add hideNoRepeat prop, filter NO_REPEAT from shortcuts - ScheduledMessageModal: pass hideNoRepeat when isEditingRecurring - Revert update_pending_on_deactivation (no longer reachable from UI) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): address CodeRabbit review feedback - ScheduledMessage#push_event_data: expose recurring_scheduled_message_id in ActionCable payloads so frontend correctly classifies children - RecurringScheduledMessagePolicy: add agent_bot? check for parity with ScheduledMessagePolicy - RecurrenceCalculatorService: guard against nil/empty week_days - Factory: bind inbox and account to conversation to prevent cross-account flakiness in specs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): update schema to enforce non-null constraint on occurrences_sent --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com> |
||
|
|
9967101b48
|
feat(rollup): add models and write path [1/3] (#13796)
## PR#1: Reporting events rollup — model and write path Reporting queries currently hit the `reporting_events` table directly. This works, but the table grows linearly with event volume, and aggregation queries (counts, averages over date ranges) get progressively slower as accounts age. This PR introduces a pre-aggregated `reporting_events_rollups` table that stores daily per-metric, per-dimension (account/agent/inbox) totals. The write path is intentionally decoupled from the read path — rollup rows are written inline from the event listener via upsert, and a backfill service exists to rebuild historical data from raw events. Nothing reads from this table yet. The write path activates when an account has a `reporting_timezone` set (new account setting). The `reporting_events_rollup` feature flag controls only the future read path, not writes — so rollup data accumulates silently once timezone is configured. A `MetricRegistry` maps raw event names to rollup column semantics in one place, keeping the write and (future) read paths aligned. ### What changed - Migration for `reporting_events_rollups` with a unique composite index for upsert - `ReportingEventsRollup` model - `reporting_timezone` account setting with IANA timezone validation - `MetricRegistry` — single source of truth for event-to-metric mappings - `RollupService` — real-time upsert from event listener - `BackfillService` — rebuilds rollups for a given account + date from raw events - Rake tasks for interactive backfill and timezone setup - `reporting_events_rollup` feature flag (disabled by default) ### How to test 1. Set a `reporting_timezone` on an account (`Account.first.update!(reporting_timezone: 'Asia/Kolkata')`) 2. Resolve a conversation or trigger a first response 3. Check `ReportingEventsRollup.where(account_id: ...)` — rows should appear 4. Run backfill: `bundle exec rake reporting_events_rollup:backfill` and verify historical data populates --------- Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com> |
||
|
|
a90ffe6264
|
feat: Add force legacy auto-resolve flag (#13804)
# Pull Request Template ## Description Add account setting and store_accessor for `captain_force_legacy_auto_resolve`. Enterprise job now skips LLM evaluation when this flag is true and falls back to legacy time-based resolution. Add spec to cover the fallback. ## Type of change We recently rolled out Captain deciding if a conversation is resolved or not. While it is an improvement for majority of customers, some still prefer the old way of auto-resolving based on inactivity. This PR adds a check. ## How Has This Been Tested? Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration. legacy_auto_resolve = true <img width="1282" height="848" alt="CleanShot 2026-03-13 at 19 55 55@2x" src="https://github.com/user-attachments/assets/dfdcc5d5-6d21-462b-87a6-a5e1b1290a8b" /> legacy_auto_resolve = false <img width="1268" height="864" alt="CleanShot 2026-03-13 at 20 00 50@2x" src="https://github.com/user-attachments/assets/f4719ec6-922a-4c3b-bc45-7b29eaced565" /> ## 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 |
||
|
|
c08fa631a9
|
feat: Add temporary account setting to disable Captain auto-resolve (#13680)
Add a temporary `captain_disable_auto_resolve` boolean setting on accounts to prevent Captain from resolving conversations. Guards both the scheduled resolution job and the assistant's resolve tool. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
9a4c5058f3 | Merge branch 'main' into chore/merge-upstream-4.11.0 | ||
|
|
8f95fafff4
|
feat: Add a setting to keep conversations pending on bot failures (#13512)
Adds an account-level setting `keep_pending_on_bot_failure` to control whether conversations should move from pending to open when agent bot webhooks fail. Some users experience occasional message drops and don't want conversations to automatically reopen due to transient bot failures. This setting gives accounts control over that behavior. This is a temporary setting which will be removed in future once a proper fix for it is done, so it is not added in the UI. |
||
|
|
c884cdefde
|
feat: add per-account daily rate limit for outbound emails (#13411)
Introduce a daily cap on non-channel outbound emails to prevent abuse. Fixes https://linear.app/chatwoot/issue/CW-6418/ses-incident-jan-28 ## Type of change - [x] New feature (non-breaking change which adds functionality) - [x] Breaking change (fix or feature that would cause existing functionality not to work as expected) ## Summary - Adds a Redis-based daily counter to rate limit outbound emails per account, preventing email abuse - Covers continuity emails (WebWidget/API), conversation transcripts, and agent notifications - Email channel replies are excluded (paid feature, not abusable) - Adds account suspension check in `ConversationReplyMailer` to block already-queued emails for suspended accounts ## Limit Resolution Hierarchy 1. Per-account override (`account.limits['emails']`) — SuperAdmin configurable 2. Enterprise plan-based (`ACCOUNT_EMAILS_PLAN_LIMITS` InstallationConfig) 3. Global default (`ACCOUNT_EMAILS_LIMIT` InstallationConfig, default: 100) 4. Fallback (`ChatwootApp.max_limit` — effectively unlimited) ## Enforcement Points | Path | Where | Behavior | |------|-------|----------| | WebWidget/API continuity | `SendEmailNotificationService#should_send_email_notification?` | Silently skipped | | Widget transcript | `Widget::ConversationsController#transcript` | Returns 429 | | API transcript | `ConversationsController#transcript` | Returns 429 | | Agent notifications | `Notification::EmailNotificationService#perform` | Silently skipped | | Email channel replies | Not rate limited | Paid feature | | Suspended accounts | `ConversationReplyMailer` | Blocked at mailer level | |
||
|
|
f9d1146cb0
|
feat: mensagens agendadas (#198)
* feat: Adds model for scheduling messages * feat: Implement scheduled message handling and processing jobs * feat: Add ScheduledMessagesController and associated specs for managing scheduled messages * refactor: Simplify scheduled message job specs and improve metadata handling * feat: Add ScheduledMessagePolicy for managing access to scheduled messages * feat: Add routes for managing scheduled messages * feat: Add scheduled message event handling and broadcasting * feat: Add JSON views for scheduled messages creation, destruction, updating, and indexing * feat: Update scheduled message status and dispatch update event after message creation * feat: Ensure scheduled message updates trigger dispatch event * feat: Add mutation types for managing scheduled messages * feat: Add additionalAttributes prop to Message component and provider * feat: Implement scheduled message handling in ActionCable and Vuex store * feat: Add unit tests for scheduled messages actions and mutations * feat: implement scheduled messages functionality - Added support for scheduling messages in the conversation dashboard. - Introduced new components: ScheduledMessageModal and ScheduledMessages for managing scheduled messages. - Enhanced ReplyBottomPanel to include scheduling options. - Updated Base.vue to handle scheduled message styling. - Integrated Vuex store module for managing scheduled messages state. - Added necessary translations for scheduled messages in English and Portuguese. * feat: add pagination to scheduled messages index and update tests accordingly * chore: update scheduled messages specs for future time validation and response status * chore: enhance scheduled messages API with pagination and add skeleton loader component * feat: add create_scheduled_message action to automation rule attributes * feat: implement create_scheduled_message action and enhance attachment handling * feat: add scheduled message functionality with UI components and localization * test: enhance scheduledMessages mutations tests with meta handling and structure * chore: update label to display file name upon successful upload in AutomationFileInput component * feat: add initialAttachment prop to ScheduledMessageModal and update ReplyBox to pass attachment * chore: prepend_mod_with to ScheduledMessagesController for better module handling * fix: attachment visibility in ScheduledMessageItem component * chore: enhance ScheduledMessage model with validations and reduce controller load * refactor: simplify ScheduledMessagesAPI methods by removing unnecessary instance variable * chore: update event emission for scheduled message creation in ReplyBox and ScheduledMessageModal * refactor: update status configuration to use label keys * chore: update date formatting in ScheduledMessageItem component * refactor: collapse logic to checkOverflow and update related functionality * chore: add author indication for current user in scheduled messages * chore: enhance scheduled message metadata with author information and localization * fix: send message shortcut * chore: handle errors in scheduled message submission * chore: update scheduled message modal to use combined date and time input * chore: refactor scheduled messages handling to remove pagination and update related tests * fix: ensure scheduled messages update status and dispatch on failure * fix: update scheduled message due date logic and simplify sending checks * refactor: rename build_message method for send_message * fix: update scheduled message creation time and improve test reliability * chore: ignore unnecessary check * chore: add scheduled message metadata handling in message builder, add scheduled message factorie and update specs * refactor: use scheduled message factorie creation in specs * chore: streamline error handling in scheduled message job and remove dispatch logic * fix: change scheduled_messages association to destroy dependent records * refactor: remove unused attributes from scheduled message payload builder * chore: update scheduled message retrieval to use conversation association * chore: correct cron format for scheduled messages job * chore: remove migration for author_type in scheduled_messages * feat: enhance scheduled messages management with delete confirmation and error handling * chore: set cron poll interval to 10 seconds for improved scheduling precision * feat: include additional_attributes in message JSON response * feat: enhance scheduled message validation and localization support * chore: update scheduled message display * Merge branch 'main' into Cayo-Oliveira/CU-86aenh268/Mensagens-agendadas * feat: add scheduled message indicators and validation for message length * fix: remove unnecessary condition from line-clamp class binding * feat: update scheduled messages localization and enhance content validation * feat: update scheduled messages order, enhance scheduledAt computation, and add message association * fix: reorder condition for Facebook channel message length computation * fix: change detection for attachments in scheduled messages * fix: remove unnecessary colon from close-on-backdrop-click prop in ScheduledMessageModal * chore: add error handling for scheduled message deletion and update localization for delete failure * fix: enforce minimum delay of 1 minute for scheduled messages and update validation * fix: remove unused private property and improve locale formatting for scheduled messages * fix: adjust positioning of DropdownBody in ReplyBottomPanel and clean up schema foreign keys * docs: add scheduled messages management APIs and payload definitions --------- Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com> |
||
|
|
04b2901e1f
|
feat: Conversation workflows(EE) (#13040)
We are expanding Chatwoot’s automation capabilities by introducing **Conversation Workflows**, a dedicated section in settings where teams can configure rules that govern how conversations are closed and what information agents must fill before resolving. This feature helps teams enforce data consistency, collect structured resolution information, and ensure downstream reporting is accurate. Instead of having auto‑resolution buried inside Account Settings, we introduced a new sidebar item: - Auto‑resolve conversations (existing behaviour) - Required attributes on resolution (new) This groups all conversation‑closing logic into a single place. #### Required Attributes on Resolve Admins can now pick which custom conversation attributes must be filled before an agent can resolve a conversation. **How it works** - Admin selects one or more attributes from the list of existing conversation level custom attributes. - These selected attributes become mandatory during resolution. - List all the attributes configured via Required Attributes (Text, Number, Link, Date, List, Checkbox) - When an agent clicks Resolve Conversation: If attributes already have values → the conversation resolves normally. If attributes are missing → a modal appears prompting the agent to fill them. <img width="1554" height="1282" alt="CleanShot 2025-12-10 at 11 42 23@2x" src="https://github.com/user-attachments/assets/4cd5d6e1-abe8-4999-accd-d4a08913b373" /> #### Custom Attributes Integration On the Custom Attributes page, we will surfaced indicators showing how each attribute is being used. Each attribute will show badges such as: - Resolution → used in the required‑on‑resolve workflow - Pre‑chat form → already existing <img width="2390" height="1822" alt="CleanShot 2025-12-10 at 11 43 42@2x" src="https://github.com/user-attachments/assets/b92a6eb7-7f6c-40e6-bf23-6a5310f2d9c5" /> #### Admin Flow - Navigate to Settings → Conversation Workflows. - Under Required attributes on resolve, click Add Required Attribute. - Pick from the dropdown list of conversation attributes. - Save changes. Agents will now be prompted automatically whenever they resolve. <img width="2434" height="872" alt="CleanShot 2025-12-10 at 11 44 42@2x" src="https://github.com/user-attachments/assets/632fc0e5-767c-4a1c-8cf4-ffe3d058d319" /> #### NOTES - The Required Attributes on Resolve modal should only appear when values are missing. - Required attributes must block the resolution action until satisfied. - Bulk‑resolve actions should follow the same rules — any conversation missing attributes cannot be bulk‑resolved, rest will be resolved, show a notification that the resolution cannot be done. - API resolution does not respect the attributes. --------- Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: iamsivin <iamsivin@gmail.com> Co-authored-by: Pranav <pranav@chatwoot.com> |
||
|
|
34b42a1ce1
|
feat: add global config for captain settings (#13141)
Co-authored-by: aakashb95 <aakashbakhle@gmail.com> Co-authored-by: Aakash Bakhle <48802744+aakashb95@users.noreply.github.com> |
||
|
|
ca5e112a8c
|
feat: TikTok channel (#12741)
fixes: #11834 This pull request introduces TikTok channel integration, enabling users to connect and manage TikTok business accounts similarly to other supported social channels. The changes span backend API endpoints, authentication helpers, webhook handling, configuration, and frontend components to support TikTok as a first-class channel. **Key Notes** * This integration is only compatible with TikTok Business Accounts * Special permissions are required to access the TikTok [Business Messaging API](https://business-api.tiktok.com/portal/docs?id=1832183871604753). * The Business Messaging API is region-restricted and is currently unavailable to users in the EU. * Only TEXT, IMAGE, and POST_SHARE messages are currently supported due to limitations in the TikTok Business Messaging API * A message will be successfully sent only if it contains text alone or one image attachment. Messages with multiple attachments or those combining text and attachments will fail and receive a descriptive error status. * Messages sent directly from the TikTok App will be synced into the system * Initiating a new conversation from the system is not permitted due to limitations from the TikTok Business Messaging API. **Backend: TikTok Channel Integration** * Added `Api::V1::Accounts::Tiktok::AuthorizationsController` to handle TikTok OAuth authorization initiation, returning the TikTok authorization URL. * Implemented `Tiktok::CallbacksController` to handle TikTok OAuth callback, process authorization results, create or update channel/inbox, and handle errors or denied scopes. * Added `Webhooks::TiktokController` to receive and verify TikTok webhook events, including signature verification and event dispatching. * Created `Tiktok::IntegrationHelper` module for JWT-based token generation and verification for secure TikTok OAuth state management. **Configuration and Feature Flags** * Added TikTok app credentials (`TIKTOK_APP_ID`, `TIKTOK_APP_SECRET`) to allowed configs and app config, and registered TikTok as a feature in the super admin features YAML. [[1]](diffhunk://#diff-5e46e1d248631a1147521477d84a54f8ba6846ea21c61eca5f70042d960467f4R43) [[2]](diffhunk://#diff-8bf37a019cab1dedea458c437bd93e34af1d6e22b1672b1d43ef6eaa4dcb7732R69) [[3]](diffhunk://#diff-123164bea29f3c096b0d018702b090d5ae670760c729141bd4169a36f5f5c1caR74-R79) **Frontend: TikTok Channel UI and Messaging Support** * Added `TiktokChannel` API client for frontend TikTok authorization requests. * Updated channel icon mappings and tests to include TikTok (`Channel::Tiktok`). [[1]](diffhunk://#diff-b852739ed45def61218d581d0de1ba73f213f55570aa5eec52aaa08f380d0e16R16) [[2]](diffhunk://#diff-3cd3ae32e94ef85f1f2c4435abf0775cc0614fb37ee25d97945cd51573ef199eR64-R69) * Enabled TikTok as a supported channel in contact forms, channel widgets, and feature toggles. [[1]](diffhunk://#diff-ec59c85e1403aaed1a7de35971fe16b7033d5cd763be590903ebf8f1ca25a010R47) [[2]](diffhunk://#diff-ec59c85e1403aaed1a7de35971fe16b7033d5cd763be590903ebf8f1ca25a010R69) [[3]](diffhunk://#diff-725b90ca7e3a6837ec8291e9f57094f6a46b3ee00e598d16564f77f32cf354b0R26-R29) [[4]](diffhunk://#diff-725b90ca7e3a6837ec8291e9f57094f6a46b3ee00e598d16564f77f32cf354b0R51-R54) [[5]](diffhunk://#diff-725b90ca7e3a6837ec8291e9f57094f6a46b3ee00e598d16564f77f32cf354b0R68) * Updated message meta logic to support TikTok-specific message statuses (sent, delivered, read). [[1]](diffhunk://#diff-e41239cf8dda36c1bd1066dbb17588ae8868e56289072c74b3a6d7ef5abdd696R23) [[2]](diffhunk://#diff-e41239cf8dda36c1bd1066dbb17588ae8868e56289072c74b3a6d7ef5abdd696L63-R65) [[3]](diffhunk://#diff-e41239cf8dda36c1bd1066dbb17588ae8868e56289072c74b3a6d7ef5abdd696L81-R84) [[4]](diffhunk://#diff-e41239cf8dda36c1bd1066dbb17588ae8868e56289072c74b3a6d7ef5abdd696L103-R107) * Added support for embedded message attachments (e.g., TikTok embeds) with a new `EmbedBubble` component and updated message rendering logic. [[1]](diffhunk://#diff-c3d701caf27d9c31e200c6143c11a11b9d8826f78aa2ce5aa107470e6fdb9d7fR31) [[2]](diffhunk://#diff-047859f9368a46d6d20177df7d6d623768488ecc38a5b1e284f958fad49add68R1-R19) [[3]](diffhunk://#diff-c3d701caf27d9c31e200c6143c11a11b9d8826f78aa2ce5aa107470e6fdb9d7fR316) [[4]](diffhunk://#diff-cbc85e7c4c8d56f2a847d0b01cd48ef36e5f87b43023bff0520fdfc707283085R52) * Adjusted reply policy and UI messaging for TikTok's 48-hour reply window. [[1]](diffhunk://#diff-0d691f6a983bd89502f91253ecf22e871314545d1e3d3b106fbfc76bf6d8e1c7R208-R210) [[2]](diffhunk://#diff-0d691f6a983bd89502f91253ecf22e871314545d1e3d3b106fbfc76bf6d8e1c7R224-R226) These changes collectively enable end-to-end TikTok channel support, from configuration and OAuth flow to webhook processing and frontend message handling. ------------ # TikTok App Setup & Configuration 1. Grant access to the Business Messaging API ([Documentation](https://business-api.tiktok.com/portal/docs?id=1832184145137922)) 2. Set the app authorization redirect URL to `https://FRONTEND_URL/tiktok/callback` 3. Update the installation config with TikTok App ID and Secret 4. Create a Business Messaging Webhook configuration and set the callback url to `https://FRONTEND_URL/webhooks/tiktok` ([Documentation](https://business-api.tiktok.com/portal/docs?id=1832190670631937)) . You can do this by calling `Tiktok::AuthClient.update_webhook_callback` from rails console once you finish Tiktok channel configuration in super admin ( will be automated in future ) 5. Enable TikTok channel feature in an account --------- Co-authored-by: Sojan Jose <sojan@pepalo.com> Co-authored-by: iamsivin <iamsivin@gmail.com> |
||
|
|
0d490640f2
|
feat: Conversation workflow backend changes (#13070)
Extracted the backend changes from https://github.com/chatwoot/chatwoot/pull/13040 - Added the support for saving `conversation_required_attributes` in account - Delete `conversation_required_attributes` if custom attribute deleted. Co-authored-by: Vinay Keerthi <11478411+stonecharioteer@users.noreply.github.com> |
||
|
|
e635122ff6
|
fix: add presence validation for account name (#12636)
## Description When a user tries creating a new account through the Super Admin dashboard, and they forget to fill in the account name, they're faced with an ugly error (generic "Something went wrong" on production). This PR simply adds the `validates :name, presence: true` model validation on `Account` model, which is translated as a proper error message on the Super Admin UI. |
||
|
|
de5fb7a405
|
chore: remove unused telegram bot model (#12417)
## Summary - remove unused TelegramBot model and its association - drop obsolete telegram_bots table |
||
|
|
341487b93e
|
feat: Add assignment policies controllers with jbuilder views (#12199)
## Linear reference: https://linear.app/chatwoot/issue/CW-4649/re-imagine-assignments ## Description This PR introduces the foundation for Assignment V2 system by implementing assignment policies and their association with inboxes. Assignment policies allow configuring how conversations are distributed among agents, with support for different assignment orders (round_robin in community, balanced in enterprise) and conversation prioritization strategies Fixes # (issue) ## Type of change Please delete options that are not relevant. - [ ] 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? Test Coverage: - Controller specs for assignment policies CRUD operations - Enterprise-specific specs for balanced assignment order - Model specs for community/enterprise separation Manual Testing: 1. Create assignment policy: POST /api/v1/accounts/{id}/assignment_policies 2. List policies: GET /api/v1/accounts/{id}/assignment_policies 3. Assign policy to inbox: POST /api/v1/accounts/{id}/assignment_policies/{id}/inboxes 4. View inbox policy: GET /api/v1/accounts/{id}/inboxes/{id}/assignment_policy 5. Verify community edition ignores "balanced" assignment order 6. Verify enterprise edition supports both "round_robin" and "balanced" - testing the flows after enterprise folder deletion ## Checklist: - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: Pranav <pranavrajs@gmail.com> Co-authored-by: Pranav <pranav@chatwoot.com> |
||
|
|
8bc00f707b
|
feat(ee): Add transcription support for audio messages (#11670)
<img width="419" alt="Screenshot 2025-06-03 at 4 25 37 PM" src="https://github.com/user-attachments/assets/4b6ddd11-9b91-4981-a571-83746cc4d40b" /> Fixes https://github.com/chatwoot/chatwoot/issues/10182 --------- Co-authored-by: Sojan Jose <sojan@pepalo.com> |
||
|
|
e9a132a923
|
feat: auto resolve label option and fixes (#11541)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com> |
||
|
|
bc42aec68e
|
chore: upgrade ruby version to 3.4.4 (#11524)
- Chore upgrade ruby version to 3.4.4 before we migrate to rails 7.2 over #11037 |
||
|
|
c87b2109a9
|
feat: allow auto resolve waiting option (#11436) | ||
|
|
b533980880
|
feat: Add support for minutes in auto resolve feature (#11269)
### Summary - Converts conversation auto-resolution duration from days to minutes for more granular control - Updates validation to allow values from 10 minutes (minimum) to 999 days (maximum) - Implements smart messaging to show appropriate time units in activity messages ### Changes - Created migration to convert existing durations from days to minutes (x1440) - Updated conversation resolver to use minutes instead of days - Added dynamic translation key selection based on duration value - Updated related specs and documentation - Added support for displaying durations in days, hours, or minutes based on value ### Test plan - Verify account validation accepts new minute-based ranges - Confirm existing account settings are correctly migrated - Test auto-resolution works properly with minute values - Ensure proper time unit display in activity messages --------- Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> |
||
|
|
1a78a9243f
|
chore: Clean up report & knowledge base policies (#11234)
- Removes the portal_members table and all associated records - Updates policies to use custom roles with knowledge_base_manage permission - Updates controllers, models, and views to work without portal membership - Adds tests for the new permission model |
||
|
|
0dc2af3c78
|
feat: Ability to delete account for administrators (#1874)
## Description Add account delete option in the user account settings. Fixes #1555 ## Type of change - [ ] New feature (non-breaking change which adds functionality)   ## Checklist: - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: Sojan Jose <sojan@pepalo.com> Co-authored-by: Sojan Jose <sojan.official@gmail.com> Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com> |
||
|
|
d9450fde4a
|
feat: Added Instagram channel migration (#11181)
This PR is part of https://github.com/chatwoot/chatwoot/pull/11054 to make the review cycle easier. |
||
|
|
3a4249da11
|
feat: Add support for multi-language support for Captain (#11068)
This PR implements the following features - FAQs from conversations will be generated in account language - Contact notes will be generated in account language - Copilot chat will respond in user language, unless the agent asks the question in a different language ## Changes ### Copilot Chat - Update the prompt to include an instruction for the language, the bot will reply in asked language, but will default to account language - Update the `ChatService` class to include pass the language to `SystemPromptsService` ### FAQ and Contact note generation - Update contact note generator and conversation generator to include account locale - Pass the account locale to `SystemPromptsService` <details><summary>Screenshots</summary> #### FAQs being generated in system langauge  #### Copilot responding in system language  </details> --------- Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com> Co-authored-by: Pranav <pranav@chatwoot.com> |
||
|
|
ecfa6bf6a2
|
feat: Add support for account abuse detection (#11001)
This PR adds service to automate account abuse detection. Currently based on the signup name and URL, could potentially add more context such as usage analysis, message metadata etc. |
||
|
|
978a8a4cb2
|
fix: support_email and inbound_email_domain returning empty string (#8963)
chore: Fix for inbound email domain being nil |
||
|
|
7776b74126
|
chore: Apply fixes for items in rubocop_todo [CW-1806] (#8864)
This PR addresses several items listed in our rubocop_todo by implementing the necessary corrections and enhancements. As a result, we are now able to remove the rubocop_todo file entirely, streamlining our codebase and ensuring adherence to our coding standards. fixes: https://linear.app/chatwoot/issue/CW-1806/chore-rubocop-audit |
||
|
|
07ea9694a3
|
feat: new accounts controller for signup+onboarding (#8804)
* feat: add v2 accounts controller * feat: allow empty account and user name * feat: ensure and is present for v1 signup * test: remove validation checks * chore: apply suggestions * chore: revert en.yml formatting * chore: line at EOF * fix: routes --------- Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com> |
||
|
|
5588d6e344
|
feat: convert feature_flag to bigint [CW-2767] (#8350)
Co-authored-by: Sojan <sojan@pepalo.com> |
||
|
|
480f34803b
|
feat: Response Bot using GPT and Webpage Sources (#7518)
This commit introduces the ability to associate response sources to an inbox, allowing external webpages to be parsed by Chatwoot. The parsed data is converted into embeddings for use with GPT models when managing customer queries. The implementation relies on the `pgvector` extension for PostgreSQL. Database migrations related to this feature are handled separately by `Features::ResponseBotService`. A future update will integrate these migrations into the default rails migrations, once compatibility with Postgres extensions across all self-hosted installation options is confirmed. Additionally, a new GitHub action has been added to the CI pipeline to ensure the execution of specs related to this feature. |
||
|
|
23ca6d56f9
|
feat: Contact Exports (#7258) | ||
|
|
385eab6b96
|
chore: Add max length validation to text fields (#7073)
Introduces a default max length validation for all string and text fields to prevent processing large payloads. |
||
|
|
271263bcc2
|
feat: SLA CRUD APIs (EE) (#7027)
Fixes: https://linear.app/chatwoot/issue/CW-1613/sla-api Co-authored-by: Sojan Jose <sojan@pepalo.com> |
||
|
|
ebd5fbef17
|
chore: Use feature_flags attribute instead of settings_flags (#6820)
* chore: Use feature_flag instead of settings_flag * Remove unnecessary changes |
||
|
|
00ee0478eb
|
feat: IndexedDB based caching for labels, inboxes and teams [CW-50] (#6710)
* feat: allow caching of labels in the account scope * feat: send cache keys in account json response * feat: kickstart web worker * feat: setup basic architecture for workers * feat: install idb * feat: add datamanger * fix: typos * refactor: rename method * feat: make init db a manual step * refactor: separate accountIdFromRoute * feat: cache enabled API client * feat: enable caching for inboxes and labels * feat: enable cache for team * feat: manage exceptions for team * feat: add team to data manager * feat: add a generic listener * refactor: send only cache keys * refactor: separate validate method * feat: add listeners * feat: add event for revalidate * feat: add cache keys endpoint * refactor: fetch cache keys instead of full account data * fix: key pattern * feat: don't fetch account for cache_keys * fix: cache key base class * refactor: cache keys helper * feat: add helper * fix: cache-key update logic * feat: delete indexeddb on logout * feat: remove worker.js * refactor: move data-manager * refactor: name of file * feat: add test for DataManager * refactor: add fake idb to jest setup * test: cache keys helper * test: cache keys helper * test: cache_keys in accounts controller * refactor: remove cache_keys context * feat: add policy for cache-keys |
||
|
|
d870b0815a
|
feat: Audit log APIs (#6434)
- Adds the appropriate APIs for Audit Logs. ref: #6015 |
||
|
|
74fdfffe08
|
fix: Notification page breakages (#5236)
- Remove the cascading foreign key indexes - Add migration to clean up existing objects fixes: #4285 |
||
|
|
e0cebfaa1a
|
chore: Allow super admin to suspend an account (#5174) | ||
|
|
0cee42a9f9
|
feat: Macros CRUD api (#5047) | ||
|
|
1dc7ce526e
|
chore: Add ee helper, custom_attributes to account (#5058) | ||
|
|
4187428729
|
chore: Update dependencies to the latest versions (#5033) | ||
|
|
713fdb44ee
|
feat (ee): APIs to configure an auto assignment limit for inboxes (#4672)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com> |
||
|
|
b9aa4444b3
|
feat: Allow users to create dashboard apps to give agents more context (#4761) | ||
|
|
938fb887c4
|
feat: Portal endpoint (#4633) | ||
|
|
ccf52a620b
|
feat: Update notifications and unread count in real time (#4261) | ||
|
|
ff881fcad9
|
chore: Support Email should give priority to environment variable (#4270)
Account.support_email should give priority to environment variables over installation config Fixes: #3304 |