Let somebody hide a direct message (GRYT-678) - #86
Merged
Conversation
Take a conversation out of your own sidebar without deleting anything. `hidden_at` goes on `conversation_members` rather than on `conversations`, and that is the whole design: each participant already has their own row there, so hiding is one person's answer about their own sidebar. A column on the conversation would have hidden it for both of them, which is a different feature and not one anybody asked for. `dm:setHidden` writes only the caller's row, and the id it writes comes from the verified token rather than the payload. A message brings it back, for whoever had hidden it. Without that, hiding is a way to never hear from somebody again and the only sign is an unread count on a row that is not there. Blocking is the feature that means the other thing; it is on the roadmap as its own item and needs its own decisions. Re-opening from the member list also un-hides, so there is a way back that does not depend on the other person saying something. The un-hide is emitted as `dm:opened`, which is the event the clients already use to put a conversation into the list — a second event that meant the same thing would be a second path to keep in step. It runs after the send and its failure is swallowed, for the same reason auto-roles are: a sidebar that has not caught up must never be why a message did not arrive. Nothing is deleted at any point. There is a test that says so. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 29, 2026
sivert-io
added a commit
to Gryt-chat/client
that referenced
this pull request
Aug 29, 2026
The client half of Gryt-chat/server#86. Right-click a conversation, choose Hide, and it leaves your sidebar. Yours alone — the other person's list does not change and they are not told — and nothing is deleted. The DM rows had no context menu at all, so this adds one. Same shape as the channel rows', with the other person's name as the group label. Hiding the conversation you are reading puts the selection back on the channels. Staying in it would leave the view pointing at something that is no longer in the list, with no way back to itself; the conversation is still readable, by opening it again from the member list. The row goes when the server says so rather than on the click. Dropping it locally would look right here and leave it on the phone until something else refreshed the list — the reason `hidden_at` is on the server is that the two agree. The item says what it does not do. "Hide" on its own reads as a soft delete to enough people that the second line is worth the room. Same wording as the mobile client, which is the same decision made once. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.
Server half. Take a conversation out of your own sidebar without deleting anything.
The design decision, and it's the one to check
hidden_atgoes onconversation_members, not onconversations. Each participant already has their own row there, so hiding is one person's answer about their own sidebar — you hiding it is invisible to them, and they get no event. A column onconversationswould have hidden it for both, which is a different feature entirely.dm:setHiddenwrites only the caller's row, and theserver_user_idit writes comes from the verified token, never the payload.A message brings it back
For whoever had hidden it. Without that, "hide" is quietly a way to never hear from someone again, and the only sign would be an unread count on a row that isn't there. Blocking is the feature that does mean that; it's on the roadmap as its own item and needs its own decisions.
Re-opening from the member list also un-hides, so there's a way back that doesn't depend on the other person saying something.
The un-hide is emitted as
dm:opened— the event both clients already use to put a conversation into the list. A second event meaning the same thing would be a second path to keep in step. It runs after the send and its failure is swallowed, same reasoning as auto-roles: a sidebar that hasn't caught up must never be why a message didn't arrive.Worth a look
dm:setHidden. It refuses a conversation that isn't yours. Today that's belt-and-braces — theUPDATEwould match no row anyway — but it's the check that keeps it harmless if the table ever gains a different key.clearConversationHiddenclears for everyone in the conversation. That looks like it contradicts "per-person", and doesn't: the hide is per-person; a new message is relevant to every participant, so it un-hides for each of them who had hidden it. It returns the ids it changed so only those people get told.Testing
Six new cases: hiding leaves the other person's list alone, history survives, it comes back on a new message and the client is told, it comes back on re-open, it can be put back by hand, and somebody else's conversation is refused.
338 pass (was 332). Typecheck clean, no new lint warnings.
Not in this PR
Client and mobile UI — right-click and long-press respectively. Both are on GRYT-678 and follow once this lands.
🤖 Generated with Claude Code