Livechat:
- Add a live widget preview that renders in the inbox settings help rail.
- Warn when the primary or header colors are too close to the background.
- Require gradient/image background values and notice banner text when enabled.
- Show a default launcher logo in the widget when none is set, matching the preview.
- Drop the Beta badge from the livechat channel.
General settings:
- Add "set agents away on login". Agents log in as away and must go online manually.
- Add "show subject in conversation list" toggle.
Other:
- Add a keyboard shortcuts dialog from the user menu.
- Show a "snoozed until" badge on snoozed conversations.
- Contact search now matches emails partially instead of exact.
- Give outgoing message bubbles a secondary background.
Address CodeRabbit review: the query deleted by message uuid alone, so an agent
with access to one conversation could delete a private note from another by
pairing an accessible cuuid with a foreign message uuid. The delete is now
scoped via conversation_id = (SELECT id FROM conversations WHERE uuid = $2), and
DeletePrivateMessage / the handler pass the conversation uuid alongside the
message uuid.
[Used Claude Code 🤖]
Right-clicking a private note shows a "Delete note" option that calls the
DELETE endpoint and removes the note from the UI. The context menu trigger is
disabled for non-private messages (browser default menu shown instead).
[Used Claude Code 🤖]
Adds DELETE /api/v1/conversations/{cuuid}/messages/{uuid} for removing private
notes via the API. Uses a dedicated `delete-private-message` query/stmt
(separate from the generic `delete-message` used internally by continuity) so
only messages with private=true can be deleted — sent/incoming messages are
protected. Returns 404 if the message doesn't exist or isn't private.
Useful for API consumers that create private notes programmatically and need to
clean them up (e.g. replacing an outdated note before adding a new one).
[Used Claude Code 🤖]
Re-derived for the v2.x contact model. insert-contact-with-external-id
already updates names on conflict; this adds the same to
insert-contact-without-external-id, preserving existing non-empty names
via COALESCE(NULLIF(EXCLUDED.first_name, ''), users.first_name).
Without this, names from the email worker and Gravity Forms never update
existing contacts.
[Used Claude Code 🤖]
Fixes typing in a filter value overwriting the whole filters object
(vee-validate listeners falling through to the builder root), the form
going stale after save/reset, and Create reusing a cancelled edit's data.
The group remove button sat inline with the first condition's close button (8px apart, easy to misclick). Move it to a labeled 'Remove group' header button (trash icon) so it's clearly distinct from the per-condition X.