feat(messages): show channel and thread location context in message cards

This commit is contained in:
MythEclipse
2026-06-03 20:34:06 +07:00
parent 79c2e31b17
commit 71801b7f77
3 changed files with 40 additions and 20 deletions
@@ -12,12 +12,19 @@ export interface MessageMetadata {
stickers?: Array<{ name?: string; url?: string }>;
attachments?: Array<{ name: string; url: string; contentType?: string }>;
embeds?: Array<{ title?: string; image?: string; thumbnail?: string }>;
channel?: {
channelId: string;
channelName?: string;
threadId?: string;
threadName?: string;
};
}
export function parseMetadata(value: string | null): MessageMetadata {
if (!value) return {};
try {
return JSON.parse(value) as MessageMetadata;
const parsed = JSON.parse(value) as MessageMetadata;
return parsed;
} catch {
return {};
}
@@ -1,6 +1,7 @@
import {
AlertCircle,
CheckCircle2,
Hash,
Image as ImageIcon,
Pencil,
RotateCw,
@@ -350,6 +351,20 @@ function MessageRow({
export function MessageCard({ messages, onReanalyze }: MessageCardProps) {
const firstMsg = messages[0];
const hasMultiple = messages.length > 1;
const meta = useMemo(
() => parseMetadata(firstMsg.metadata),
[firstMsg.metadata],
);
const channelMeta = meta.channel;
const locationLabel = useMemo(() => {
if (channelMeta?.threadName) {
return `# ${channelMeta.channelName || "unknown"} ${channelMeta.threadName}`;
}
if (channelMeta?.channelName) {
return `# ${channelMeta.channelName}`;
}
return null;
}, [channelMeta]);
return (
<article
@@ -369,11 +384,17 @@ export function MessageCard({ messages, onReanalyze }: MessageCardProps) {
/>
<div className="min-w-0 flex-1">
{/* Group header: username + timestamp of first message */}
{/* Group header: username + location + timestamp */}
<div className="flex items-baseline gap-2 mb-2">
<span className="font-semibold text-sm text-foreground">
{firstMsg.username || firstMsg.user_id}
</span>
{locationLabel && (
<span className="flex items-center gap-1 text-[11px] text-muted-foreground/50 bg-muted/50 px-1.5 py-0.5 rounded-full">
<Hash className="h-2.5 w-2.5" />
{locationLabel}
</span>
)}
<span
className="text-[11px] text-muted-foreground/60"
title={new Date(firstMsg.created_at).toLocaleString()}
@@ -12,10 +12,6 @@ import {
CardTitle,
Input,
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
Tabs,
TabsContent,
TabsList,
@@ -134,20 +130,16 @@ export function MessagesPanel({
<Hash className="h-4 w-4 text-muted-foreground shrink-0" />
<Select
value={selectedChannel || ""}
onValueChange={(val) => onChannelChange?.(val)}
>
<SelectTrigger className="w-full max-w-xs h-9 text-sm">
<SelectValue placeholder="All channels" />
</SelectTrigger>
<SelectContent>
<SelectItem value="__all">All channels</SelectItem>
{textChannels.map((ch) => (
<SelectItem key={ch.id} value={ch.id}>
# {ch.name}
</SelectItem>
))}
</SelectContent>
</Select>
onChange={(e) => onChannelChange?.(e.target.value === "__all" ? "" : e.target.value)}
placeholder="All channels"
options={[
{ value: "__all", label: "All channels" },
...textChannels.map((ch) => ({
value: ch.id,
label: `# ${ch.name}`,
})),
]}
/>
</div>
)}
</CardContent>