Edit and soft-delete private notes#290
Open
mageaustralia wants to merge 2 commits intoabhinavxd:mainfrom
Open
Conversation
Adds PUT and DELETE for /conversations/:cuuid/messages/:uuid/note. Only
the agent who authored the note can mutate it. Delete is a soft-delete:
the row stays, content is replaced with a tombstone naming the actor,
and meta.deleted=true so the UI can hide further controls.
Also fixes three reactivity bugs the new flow exposed:
- MessageCache.updateMessage was Object.assign-ing in place; consumers
holding the message ref never saw the change. Now swaps the array
entry to a new object so Vue picks up the identity change.
- conversationMessages computed didn't depend on messages.version, so
in-place cache updates couldn't trigger a re-render. Now reads the
version.
- <Letter> in MessageBubble doesn't react to its :html prop changing.
Added :key="sanitizedContent" to force remount on content change.
abhinavxd
reviewed
Apr 25, 2026
| // content with a tombstone naming the actor and setting `meta.deleted=true`. | ||
| // The row stays in the table so the audit trail is preserved. | ||
| func (m *Manager) SoftDeletePrivateNote(uuid, actorName string) error { | ||
| tombstone := fmt.Sprintf("This note was deleted by %s", actorName) |
Owner
There was a problem hiding this comment.
Can we just show "Deleted" (translated) as the bubble content, without the actor name?
The bubble already shows the sender's name above it, and since an agent can only delete their own private notes, the deleter is always the same as the author.
Showing the name a second time is redundant.
abhinavxd
reviewed
Apr 25, 2026
| emitter.emit(EMITTER_EVENTS.SHOW_TOAST, { | ||
| variant: 'destructive', | ||
| title: t('globals.messages.delete'), | ||
| description: err?.response?.data?.message || err.message |
Owner
There was a problem hiding this comment.
There's already a utility for this
import { handleHTTPError } from '@shared-ui/utils/http.js'
e.g. usage
emitter.emit(EMITTER_EVENTS.SHOW_TOAST, {
variant: 'destructive',
description: handleHTTPError(err).message
})
abhinavxd
reviewed
Apr 25, 2026
| if err != nil { | ||
| return sendErrorEnvelope(r, err) | ||
| } | ||
| if msg.ConversationUUID != cuuid || !msg.Private || msg.SenderType != cmodels.SenderTypeAgent || msg.SenderID != user.ID { |
Owner
There was a problem hiding this comment.
The ownership/private-note check is duplicated in handleUpdatePrivateNote and handleDeletePrivateNote. Worth pulling into a small helper so the rule lives in one place.
Owner
|
Added a few comments. Once those are addressed we can get this merged. |
- Replace ad-hoc `err?.response?.data?.message || err.message` toasts in MessageBubble.vue with the existing `handleHTTPError` utility from `@shared-ui/utils/http.js`. Same shape as the rest of the codebase. - Extract the duplicated 'is the caller the author of a private note on this conversation' check from `handleUpdatePrivateNote` and `handleDeletePrivateNote` into a single `loadOwnedPrivateNote` helper. The ownership rule now lives in one place.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PUTandDELETE /conversations/:cuuid/messages/:uuid/note(permmessages:write)private = true AND type = 'outgoing'so a public reply can't be touched accidentallyThis note was deleted by <Name>), andmeta.deleted = trueso the UI hides further edit/delete controls. Audit trail is preserved.Reactivity fixes that the new flow exposed
MessageCache.updateMessagewasObject.assign-ing in place, so consumers holding the message ref never saw the change. Now swaps the array entry to a new object so Vue picks up the identity change.conversationMessagescomputed didn't depend onmessages.version, so in-place cache updates couldn't trigger a re-render. Now reads the version.<Letter>inMessageBubbledoesn't react to its:htmlprop changing. Added:key="sanitizedContent"so vue-letter remounts on content change.Test plan
curl -XPUTa non-private message → 403curl -XDELETEanother agent's private note (with valid session) → 403conversation_messageswithmeta -> 'deleted' = true