mirror of
https://github.com/open-webui/open-webui.git
synced 2025-12-12 04:15:25 +00:00
enh: message reaction user names
This commit is contained in:
parent
fb6b18faef
commit
05e79bdd0c
3 changed files with 63 additions and 17 deletions
|
|
@ -5,7 +5,7 @@ from typing import Optional
|
||||||
|
|
||||||
from open_webui.internal.db import Base, get_db
|
from open_webui.internal.db import Base, get_db
|
||||||
from open_webui.models.tags import TagModel, Tag, Tags
|
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
|
from open_webui.models.channels import Channels, ChannelMember
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -100,7 +100,7 @@ class MessageForm(BaseModel):
|
||||||
|
|
||||||
class Reactions(BaseModel):
|
class Reactions(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
user_ids: list[str]
|
users: list[dict]
|
||||||
count: int
|
count: int
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -389,17 +389,30 @@ class MessageTable:
|
||||||
|
|
||||||
def get_reactions_by_message_id(self, id: str) -> list[Reactions]:
|
def get_reactions_by_message_id(self, id: str) -> list[Reactions]:
|
||||||
with get_db() as db:
|
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 = {}
|
reactions = {}
|
||||||
for reaction in all_reactions:
|
|
||||||
|
for reaction, user in results:
|
||||||
if reaction.name not in reactions:
|
if reaction.name not in reactions:
|
||||||
reactions[reaction.name] = {
|
reactions[reaction.name] = {
|
||||||
"name": reaction.name,
|
"name": reaction.name,
|
||||||
"user_ids": [],
|
"users": [],
|
||||||
"count": 0,
|
"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
|
reactions[reaction.name]["count"] += 1
|
||||||
|
|
||||||
return [Reactions(**reaction) for reaction in reactions.values()]
|
return [Reactions(**reaction) for reaction in reactions.values()]
|
||||||
|
|
|
||||||
|
|
@ -197,8 +197,8 @@
|
||||||
const reaction = m.reactions.find((reaction) => reaction.name === name);
|
const reaction = m.reactions.find((reaction) => reaction.name === name);
|
||||||
|
|
||||||
if (reaction) {
|
if (reaction) {
|
||||||
reaction.user_ids = reaction.user_ids.filter((id) => id !== $user?.id);
|
reaction.users = reaction.users.filter((u) => u.id !== $user?.id);
|
||||||
reaction.count = reaction.user_ids.length;
|
reaction.count = reaction.users.length;
|
||||||
|
|
||||||
if (reaction.count === 0) {
|
if (reaction.count === 0) {
|
||||||
m.reactions = m.reactions.filter((r) => r.name !== name);
|
m.reactions = m.reactions.filter((r) => r.name !== name);
|
||||||
|
|
@ -224,12 +224,12 @@
|
||||||
const reaction = m.reactions.find((reaction) => reaction.name === name);
|
const reaction = m.reactions.find((reaction) => reaction.name === name);
|
||||||
|
|
||||||
if (reaction) {
|
if (reaction) {
|
||||||
reaction.user_ids.push($user?.id);
|
reaction.users.push({ id: $user?.id, name: $user?.name });
|
||||||
reaction.count = reaction.user_ids.length;
|
reaction.count = reaction.users.length;
|
||||||
} else {
|
} else {
|
||||||
m.reactions.push({
|
m.reactions.push({
|
||||||
name: name,
|
name: name,
|
||||||
user_ids: [$user?.id],
|
users: [{ id: $user?.id, name: $user?.name }],
|
||||||
count: 1
|
count: 1
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -398,11 +398,44 @@
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-center flex-wrap gap-y-1.5 gap-1 mt-1 mb-2">
|
<div class="flex items-center flex-wrap gap-y-1.5 gap-1 mt-1 mb-2">
|
||||||
{#each message.reactions as reaction}
|
{#each message.reactions as reaction}
|
||||||
<Tooltip content={`:${reaction.name}:`}>
|
<Tooltip
|
||||||
|
content={$i18n.t('{{NAMES}} reacted with {{REACTION}}', {
|
||||||
|
NAMES: reaction.users
|
||||||
|
.reduce((acc, u, idx) => {
|
||||||
|
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}:`
|
||||||
|
})}
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
class="flex items-center gap-1.5 transition rounded-xl px-2 py-1 cursor-pointer {reaction.user_ids.includes(
|
class="flex items-center gap-1.5 transition rounded-xl px-2 py-1 cursor-pointer {reaction.users
|
||||||
$user?.id
|
.map((u) => u.id)
|
||||||
)
|
.includes($user?.id)
|
||||||
? ' bg-blue-300/10 outline outline-blue-500/50 outline-1'
|
? ' bg-blue-300/10 outline outline-blue-500/50 outline-1'
|
||||||
: 'bg-gray-300/10 dark:bg-gray-500/10 hover:outline hover:outline-gray-700/30 dark:hover:outline-gray-300/30 hover:outline-1'}"
|
: 'bg-gray-300/10 dark:bg-gray-500/10 hover:outline hover:outline-gray-700/30 dark:hover:outline-gray-300/30 hover:outline-1'}"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
|
|
@ -413,9 +446,9 @@
|
||||||
>
|
>
|
||||||
<Emoji shortCode={reaction.name} />
|
<Emoji shortCode={reaction.name} />
|
||||||
|
|
||||||
{#if reaction.user_ids.length > 0}
|
{#if reaction.users.length > 0}
|
||||||
<div class="text-xs font-medium text-gray-500 dark:text-gray-400">
|
<div class="text-xs font-medium text-gray-500 dark:text-gray-400">
|
||||||
{reaction.user_ids?.length}
|
{reaction.users?.length}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue