mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-15 08:17:09 +00:00
feat: Add user and chat ID filtering to the events page and store event user/chat IDs.
This commit is contained in:
1 parent
c8cd63dbe8
commit
4e7d55ff37
2 files changed
+84
-4
No files matched your search
@@ -28,6 +28,8 @@ export function EventsPage() {
|
||||
|
||||
const [categoryFilter, setCategoryFilter] = useState("all");
|
||||
const [teamFilter, setTeamFilter] = useState<string>("all");
|
||||
const [userFilter, setUserFilter] = useState<string>("all");
|
||||
const [chatFilter, setChatFilter] = useState<string>("all");
|
||||
const [isAtBottom, setIsAtBottom] = useState(true);
|
||||
const feedRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@@ -65,17 +67,47 @@ export function EventsPage() {
|
||||
return Array.from(ids);
|
||||
}, [allEvents]);
|
||||
|
||||
// Unique user IDs from events for filter dropdown
|
||||
const uniqueUsers = useMemo(() => {
|
||||
const ids = new Set<string>();
|
||||
for (const e of allEvents) {
|
||||
if (e.userId) ids.add(e.userId);
|
||||
}
|
||||
return Array.from(ids).sort();
|
||||
}, [allEvents]);
|
||||
|
||||
// Unique chat IDs from events for filter dropdown
|
||||
const uniqueChats = useMemo(() => {
|
||||
const ids = new Set<string>();
|
||||
for (const e of allEvents) {
|
||||
if (e.chatId) ids.add(e.chatId);
|
||||
}
|
||||
return Array.from(ids).sort();
|
||||
}, [allEvents]);
|
||||
|
||||
// Apply team filter
|
||||
const teamFilteredEvents = useMemo(() => {
|
||||
if (teamFilter === "all") return allEvents;
|
||||
return allEvents.filter((e) => e.teamId === teamFilter);
|
||||
}, [allEvents, teamFilter]);
|
||||
|
||||
// Apply user filter
|
||||
const userFilteredEvents = useMemo(() => {
|
||||
if (userFilter === "all") return teamFilteredEvents;
|
||||
return teamFilteredEvents.filter((e) => e.userId === userFilter);
|
||||
}, [teamFilteredEvents, userFilter]);
|
||||
|
||||
// Apply chat filter
|
||||
const chatFilteredEvents = useMemo(() => {
|
||||
if (chatFilter === "all") return userFilteredEvents;
|
||||
return userFilteredEvents.filter((e) => e.chatId === chatFilter);
|
||||
}, [userFilteredEvents, chatFilter]);
|
||||
|
||||
// Apply category filter
|
||||
const filteredEvents = useMemo(() => {
|
||||
if (categoryFilter === "all") return teamFilteredEvents;
|
||||
if (categoryFilter === "all") return chatFilteredEvents;
|
||||
if (categoryFilter === "team.crud") {
|
||||
return teamFilteredEvents.filter(
|
||||
return chatFilteredEvents.filter(
|
||||
(e) =>
|
||||
e.event === "team.created" ||
|
||||
e.event === "team.updated" ||
|
||||
@@ -83,8 +115,8 @@ export function EventsPage() {
|
||||
e.event.startsWith("team.member."),
|
||||
);
|
||||
}
|
||||
return teamFilteredEvents.filter((e) => e.event.startsWith(categoryFilter));
|
||||
}, [teamFilteredEvents, categoryFilter]);
|
||||
return userFilteredEvents.filter((e) => e.event.startsWith(categoryFilter));
|
||||
}, [chatFilteredEvents, categoryFilter]);
|
||||
|
||||
// Auto-scroll to bottom when new events arrive
|
||||
useEffect(() => {
|
||||
@@ -175,6 +207,34 @@ export function EventsPage() {
|
||||
))}
|
||||
</select>
|
||||
)}
|
||||
|
||||
{/* User filter */}
|
||||
<select
|
||||
value={userFilter}
|
||||
onChange={(e) => setUserFilter(e.target.value)}
|
||||
className="h-7 rounded-md border bg-background px-2 text-xs"
|
||||
>
|
||||
<option value="all">All users</option>
|
||||
{uniqueUsers.map((uid) => (
|
||||
<option key={uid} value={uid}>
|
||||
{uid}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
{/* Chat filter */}
|
||||
<select
|
||||
value={chatFilter}
|
||||
onChange={(e) => setChatFilter(e.target.value)}
|
||||
className="h-7 rounded-md border bg-background px-2 text-xs"
|
||||
>
|
||||
<option value="all">All chats</option>
|
||||
{uniqueChats.map((cid) => (
|
||||
<option key={cid} value={cid}>
|
||||
{cid}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* Event feed */}
|
||||
|
||||
@@ -11,6 +11,8 @@ export interface TeamEventEntry {
|
||||
payload: unknown;
|
||||
timestamp: number;
|
||||
teamId: string | null;
|
||||
userId: string | null;
|
||||
chatId: string | null;
|
||||
}
|
||||
|
||||
interface TeamEventState {
|
||||
@@ -34,6 +36,22 @@ function extractTeamId(payload: unknown): string | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
function extractUserId(payload: unknown): string | null {
|
||||
if (!payload || typeof payload !== "object") return null;
|
||||
const p = payload as Record<string, unknown>;
|
||||
if (typeof p.user_id === "string" && p.user_id) return p.user_id;
|
||||
if (typeof p.userId === "string" && p.userId) return p.userId;
|
||||
return null;
|
||||
}
|
||||
|
||||
function extractChatId(payload: unknown): string | null {
|
||||
if (!payload || typeof payload !== "object") return null;
|
||||
const p = payload as Record<string, unknown>;
|
||||
if (typeof p.chat_id === "string" && p.chat_id) return p.chat_id;
|
||||
if (typeof p.chatId === "string" && p.chatId) return p.chatId;
|
||||
return null;
|
||||
}
|
||||
|
||||
function loadPersistedEvents(): TeamEventEntry[] {
|
||||
try {
|
||||
const raw = localStorage.getItem(PERSIST_KEY);
|
||||
@@ -71,6 +89,8 @@ export const useTeamEventStore = create<TeamEventState>((set) => ({
|
||||
payload,
|
||||
timestamp: Date.now(),
|
||||
teamId: extractTeamId(payload),
|
||||
userId: extractUserId(payload),
|
||||
chatId: extractChatId(payload),
|
||||
};
|
||||
const next = [...s.events, entry];
|
||||
const trimmed = next.length > MAX_EVENTS ? next.slice(next.length - MAX_EVENTS) : next;
|
||||
|
||||
Reference in new issue
Block a user