From a24a5e7dfd192fa3fdfc70c087bf94e62edfe36a Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Wed, 3 Jun 2026 20:53:47 +0700 Subject: [PATCH] refactor(messages): remove text channel filter and channel-section grouping --- services/frontend/src/App.tsx | 31 +------ .../messages/components/MessageFeed.tsx | 89 +++---------------- .../features/messages/hooks/useMessages.ts | 7 +- .../frontend/src/features/messages/index.tsx | 28 +----- 4 files changed, 18 insertions(+), 137 deletions(-) diff --git a/services/frontend/src/App.tsx b/services/frontend/src/App.tsx index fac480c..e90d1ea 100644 --- a/services/frontend/src/App.tsx +++ b/services/frontend/src/App.tsx @@ -11,9 +11,7 @@ import { } from "./features/messages/hooks/useMessages"; import { type ActiveSpeaker, - type Channel, getAppConfig, - getTextChannels, type MediaState, type MessageRecord, } from "./shared/api/client"; @@ -62,8 +60,6 @@ export default function App() { !!localStorage.getItem("admin-password"), ); const [monitorGuildId, setMonitorGuildId] = useState(""); - const [textChannels, setTextChannels] = useState([]); - const [selectedMessageChannel, setSelectedMessageChannel] = useState(""); const audio = useAudioPlayback(); const activeTab = uiState.activeTab || "live"; @@ -117,7 +113,7 @@ export default function App() { }, onAttachmentUploaded: () => messages - .fetchMessages(monitorGuildId || undefined, selectedMessageChannel || undefined) + .fetchMessages(monitorGuildId || undefined) .catch(() => undefined), onMediaState: (state) => media.setMediaState(state as MediaState), onVoiceRecordingUploaded: (d) => @@ -145,38 +141,22 @@ export default function App() { voice.loadVoiceChannels(selectedVoiceGuild).catch(() => undefined); }, [selectedVoiceGuild, voice.loadVoiceChannels]); - // Load text channels when monitor guild changes (Messages tab) - useEffect(() => { - if (monitorGuildId) - getTextChannels(monitorGuildId) - .then(setTextChannels) - .catch(() => undefined); - }, [monitorGuildId]); - // Auto-fetch messages for the monitor guild useEffect(() => { if (monitorGuildId) messages - .fetchMessages(monitorGuildId, selectedMessageChannel || undefined) + .fetchMessages(monitorGuildId) .catch(() => undefined); }, [monitorGuildId, messages.fetchMessages]); - // Re-fetch when channel filter changes - useEffect(() => { - if (monitorGuildId) - messages - .fetchMessages(monitorGuildId, selectedMessageChannel || undefined) - .catch(() => undefined); - }, [selectedMessageChannel, monitorGuildId, messages.fetchMessages]); - // Periodic refetch — keeps dashboard in sync even if WS events missed useEffect(() => { if (!monitorGuildId) return; const interval = setInterval(() => { - messages.fetchMessages(monitorGuildId, selectedMessageChannel || undefined).catch(() => undefined); + messages.fetchMessages(monitorGuildId).catch(() => undefined); }, 15_000); return () => clearInterval(interval); - }, [monitorGuildId, messages.fetchMessages, selectedMessageChannel]); + }, [monitorGuildId, messages.fetchMessages]); return ( ) : ( diff --git a/services/frontend/src/features/messages/components/MessageFeed.tsx b/services/frontend/src/features/messages/components/MessageFeed.tsx index 94dcfe8..60a543e 100644 --- a/services/frontend/src/features/messages/components/MessageFeed.tsx +++ b/services/frontend/src/features/messages/components/MessageFeed.tsx @@ -1,7 +1,5 @@ import { motion } from "framer-motion"; -import { Hash } from "lucide-react"; import { useEffect, useMemo, useRef } from "react"; -import { parseMetadata } from "../../../entities/message/types"; import type { MessageRecord } from "../../../shared/api/client"; import { cardItem, cardStagger } from "../../../shared/hooks/useFramerStagger"; import { ScrollArea, EmptyStateMascot } from "../../../shared/ui"; @@ -20,12 +18,12 @@ export interface MessageFeedProps { /** Messages from the same user within 5 minutes are visually grouped. */ const GROUP_WINDOW_MS = 5 * 60 * 1000; -interface UserMessageGroup { +interface MessageGroup { messages: MessageRecord[]; } -function groupByUser(messages: MessageRecord[]): UserMessageGroup[] { - const groups: UserMessageGroup[] = []; +function groupMessages(messages: MessageRecord[]): MessageGroup[] { + const groups: MessageGroup[] = []; for (const msg of messages) { const lastGroup = groups[groups.length - 1]; if ( @@ -43,57 +41,6 @@ function groupByUser(messages: MessageRecord[]): UserMessageGroup[] { return groups; } -interface ChannelSection { - key: string; - channelId: string; - threadId: string | null; - label: string; - groups: UserMessageGroup[]; -} - -function computeChannelSections(messages: MessageRecord[]): ChannelSection[] { - if (messages.length === 0) return []; - - // Group by (channel_id, thread_id) - const map = new Map(); - for (const msg of messages) { - const key = msg.thread_id - ? `${msg.channel_id}:t:${msg.thread_id}` - : msg.channel_id; - const list = map.get(key); - if (list) list.push(msg); - else map.set(key, [msg]); - } - - const sections: ChannelSection[] = []; - for (const [key, channelMessages] of map) { - const first = channelMessages[0]; - const meta = parseMetadata(first.metadata); - const ch = meta?.channel; - - let label: string; - if (ch?.threadName && ch?.channelName) { - label = `# ${ch.channelName} › ${ch.threadName}`; - } else if (ch?.channelName) { - label = `# ${ch.channelName}`; - } else if (first.thread_id) { - label = `thread:${first.thread_id.slice(0, 8)}`; - } else { - label = `# ${first.channel_id.slice(0, 8)}`; - } - - sections.push({ - key, - channelId: first.channel_id, - threadId: first.thread_id, - label, - groups: groupByUser(channelMessages), - }); - } - - return sections; -} - export function MessageFeed({ messages, onReanalyze, @@ -121,7 +68,7 @@ export function MessageFeed({ return () => observer.disconnect(); }, [onLoadMore, hasMore]); - const sections = useMemo(() => computeChannelSections(messages), [messages]); + const groupedMessages = useMemo(() => groupMessages(messages), [messages]); if (loading) { return ( @@ -147,27 +94,13 @@ export function MessageFeed({ initial="initial" animate="animate" > - {sections.map((section) => ( -
- {/* Channel/Thread section header */} -
- - - {section.label} - -
- -
- {section.groups.map((group) => ( - - - - ))} -
-
+ {groupedMessages.map((group) => ( + + + ))} {/* Infinite-scroll sentinel */} diff --git a/services/frontend/src/features/messages/hooks/useMessages.ts b/services/frontend/src/features/messages/hooks/useMessages.ts index 198558f..80126ea 100644 --- a/services/frontend/src/features/messages/hooks/useMessages.ts +++ b/services/frontend/src/features/messages/hooks/useMessages.ts @@ -29,9 +29,8 @@ export function useMessages() { const [cursor, setCursor] = useState(null); const [hasMore, setHasMore] = useState(false); const currentGuild = useRef(null); - const currentChannel = useRef(undefined); - const fetchMessages = useCallback(async (guildId?: string, channelId?: string) => { + const fetchMessages = useCallback(async (guildId?: string) => { if (!guildId) { setMessages([]); setCursor(null); @@ -39,13 +38,11 @@ export function useMessages() { return []; } currentGuild.current = guildId; - currentChannel.current = channelId; setLoading(true); setError(null); try { const result = await listMessages({ guildId, - channelId, limit: PAGE_SIZE, }); if (currentGuild.current === guildId) { @@ -69,7 +66,6 @@ export function useMessages() { try { const result = await listMessages({ guildId: currentGuild.current, - channelId: currentChannel.current, cursor, limit: PAGE_SIZE, }); @@ -113,7 +109,6 @@ export function useMessages() { ); const { count } = await reanalyzeErrorBatch({ guildId: currentGuild.current ?? undefined, - channelId: currentChannel.current, }); return count; }, []); diff --git a/services/frontend/src/features/messages/index.tsx b/services/frontend/src/features/messages/index.tsx index e7bcbf3..d682e80 100644 --- a/services/frontend/src/features/messages/index.tsx +++ b/services/frontend/src/features/messages/index.tsx @@ -1,7 +1,7 @@ import { motion } from "framer-motion"; -import { Filter, Hash, RotateCw, Search, X } from "lucide-react"; +import { Filter, RotateCw, Search, X } from "lucide-react"; import { useMemo, useState } from "react"; -import type { Channel, MessageRecord } from "../../shared/api/client"; +import type { MessageRecord } from "../../shared/api/client"; import { cardItem, cardStagger } from "../../shared/hooks/useFramerStagger"; import { Badge, @@ -11,7 +11,6 @@ import { CardHeader, CardTitle, Input, - Select, Tabs, TabsContent, TabsList, @@ -28,9 +27,6 @@ interface MessagesPanelProps { onLoadMore?: () => void; hasMore?: boolean; loadingMore?: boolean; - textChannels?: Channel[]; - selectedChannel?: string; - onChannelChange?: (channelId: string) => void; } type AiFilter = "all" | "clean" | "flagged" | "error" | "pending"; @@ -43,9 +39,6 @@ export function MessagesPanel({ onLoadMore, hasMore, loadingMore, - textChannels, - selectedChannel, - onChannelChange, }: MessagesPanelProps) { const [searchQuery, setSearchQuery] = useState(""); const [searchResults, setSearchResults] = useState([]); @@ -125,23 +118,6 @@ export function MessagesPanel({ Messages are automatically captured from all text channels in the monitored guild. Real-time updates arrive via WebSocket.

- {textChannels && textChannels.length > 0 && ( -
- -