From 05e79bdd0c7af70b631e958924e3656db1013b80 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sat, 29 Nov 2025 13:54:52 -0500 Subject: [PATCH] enh: message reaction user names --- backend/open_webui/models/messages.py | 25 ++++++++--- src/lib/components/channel/Messages.svelte | 10 ++--- .../channel/Messages/Message.svelte | 45 ++++++++++++++++--- 3 files changed, 63 insertions(+), 17 deletions(-) diff --git a/backend/open_webui/models/messages.py b/backend/open_webui/models/messages.py index 2351c4c54c..00a3b4fa2d 100644 --- a/backend/open_webui/models/messages.py +++ b/backend/open_webui/models/messages.py @@ -5,7 +5,7 @@ from typing import Optional from open_webui.internal.db import Base, get_db from open_webui.models.tags import TagModel, Tag, Tags -from open_webui.models.users import Users, UserNameResponse +from open_webui.models.users import Users, User, UserNameResponse from open_webui.models.channels import Channels, ChannelMember @@ -100,7 +100,7 @@ class MessageForm(BaseModel): class Reactions(BaseModel): name: str - user_ids: list[str] + users: list[dict] count: int @@ -389,17 +389,30 @@ class MessageTable: def get_reactions_by_message_id(self, id: str) -> list[Reactions]: with get_db() as db: - all_reactions = db.query(MessageReaction).filter_by(message_id=id).all() + # JOIN User so all user info is fetched in one query + results = ( + db.query(MessageReaction, User) + .join(User, MessageReaction.user_id == User.id) + .filter(MessageReaction.message_id == id) + .all() + ) reactions = {} - for reaction in all_reactions: + + for reaction, user in results: if reaction.name not in reactions: reactions[reaction.name] = { "name": reaction.name, - "user_ids": [], + "users": [], "count": 0, } - reactions[reaction.name]["user_ids"].append(reaction.user_id) + + reactions[reaction.name]["users"].append( + { + "id": user.id, + "name": user.name, + } + ) reactions[reaction.name]["count"] += 1 return [Reactions(**reaction) for reaction in reactions.values()] diff --git a/src/lib/components/channel/Messages.svelte b/src/lib/components/channel/Messages.svelte index 05dabfd749..e96e2fbc36 100644 --- a/src/lib/components/channel/Messages.svelte +++ b/src/lib/components/channel/Messages.svelte @@ -197,8 +197,8 @@ const reaction = m.reactions.find((reaction) => reaction.name === name); if (reaction) { - reaction.user_ids = reaction.user_ids.filter((id) => id !== $user?.id); - reaction.count = reaction.user_ids.length; + reaction.users = reaction.users.filter((u) => u.id !== $user?.id); + reaction.count = reaction.users.length; if (reaction.count === 0) { m.reactions = m.reactions.filter((r) => r.name !== name); @@ -224,12 +224,12 @@ const reaction = m.reactions.find((reaction) => reaction.name === name); if (reaction) { - reaction.user_ids.push($user?.id); - reaction.count = reaction.user_ids.length; + reaction.users.push({ id: $user?.id, name: $user?.name }); + reaction.count = reaction.users.length; } else { m.reactions.push({ name: name, - user_ids: [$user?.id], + users: [{ id: $user?.id, name: $user?.name }], count: 1 }); } diff --git a/src/lib/components/channel/Messages/Message.svelte b/src/lib/components/channel/Messages/Message.svelte index dd93ecc2d4..0ffb76fd7e 100644 --- a/src/lib/components/channel/Messages/Message.svelte +++ b/src/lib/components/channel/Messages/Message.svelte @@ -398,11 +398,44 @@
{#each message.reactions as reaction} - + { + const name = u.id === $user?.id ? $i18n.t('You') : u.name; + const total = reaction.users.length; + + // First three names always added normally + if (idx < 3) { + const separator = + idx === 0 + ? '' + : idx === Math.min(2, total - 1) + ? ` ${$i18n.t('and')} ` + : ', '; + return `${acc}${separator}${name}`; + } + + // More than 4 → "and X others" + if (idx === 3 && total > 4) { + return ( + acc + + ` ${$i18n.t('and {{COUNT}} others', { + COUNT: total - 3 + })}` + ); + } + + return acc; + }, '') + .trim(), + REACTION: `:${reaction.name}:` + })} + >