From 2d85b63775004d000538866c4967e57b14b6068b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=20Jurmanovi=C4=87?= Date: Mon, 23 Mar 2026 22:12:10 +0100 Subject: [PATCH] feat: add server column to global activity log --- src/app/dashboard/activity-log/page.tsx | 7 +- .../activityLog/ActivityLogTable.tsx | 87 ++++++++++++------- src/lib/actions/activityLog.ts | 20 +---- src/lib/api/server/activityLog.ts | 21 ++--- src/lib/schemas/activityLog.ts | 10 +++ 5 files changed, 81 insertions(+), 64 deletions(-) diff --git a/src/app/dashboard/activity-log/page.tsx b/src/app/dashboard/activity-log/page.tsx index 1169196..191a2a8 100644 --- a/src/app/dashboard/activity-log/page.tsx +++ b/src/app/dashboard/activity-log/page.tsx @@ -1,13 +1,16 @@ import { requireAuth } from '@/lib/auth/server'; +import { getServers } from '@/lib/api/server/servers'; import { ActivityLogTable } from '@/components/activityLog/ActivityLogTable'; export default async function ActivityLogPage() { - await requireAuth(); + const session = await requireAuth(); + const servers = await getServers(session.token!); + const serverOptions = servers.map((s) => ({ id: s.id, name: s.name })); return (

Activity Log

- +
); } diff --git a/src/components/activityLog/ActivityLogTable.tsx b/src/components/activityLog/ActivityLogTable.tsx index 476b8c8..3ffe7fd 100644 --- a/src/components/activityLog/ActivityLogTable.tsx +++ b/src/components/activityLog/ActivityLogTable.tsx @@ -8,8 +8,14 @@ import { Button } from '@/components/ui/Button'; const PAGE_SIZE = 10; +interface ServerOption { + id: string; + name: string; +} + interface ActivityLogTableProps { serverId?: string; + servers?: ServerOption[]; } function formatDate(iso: string): string { @@ -47,7 +53,7 @@ const ACTION_BADGE: Record = { leaderboard_update: 'bg-overlay text-muted' }; -export function ActivityLogTable({ serverId }: ActivityLogTableProps) { +export function ActivityLogTable({ serverId, servers }: ActivityLogTableProps) { const [logs, setLogs] = useState([]); const [page, setPage] = useState(1); const [hasMore, setHasMore] = useState(true); @@ -55,6 +61,7 @@ export function ActivityLogTable({ serverId }: ActivityLogTableProps) { const [error, setError] = useState(null); const [filterAction, setFilterAction] = useState(''); + const [filterServerId, setFilterServerId] = useState(''); const [filterStartDate, setFilterStartDate] = useState(''); const [filterEndDate, setFilterEndDate] = useState(''); @@ -65,9 +72,8 @@ export function ActivityLogTable({ serverId }: ActivityLogTableProps) { setIsLoading(true); setError(null); const params = { ...filter, page: currentPage, page_size: PAGE_SIZE }; - const result = serverId - ? await getActivityLogAction(serverId, params) - : await getGlobalActivityLogAction(params); + if (serverId) params.server_id = serverId; + const result = await getActivityLogAction(params); setIsLoading(false); if (!result.success) { setError(result.message); @@ -86,6 +92,7 @@ export function ActivityLogTable({ serverId }: ActivityLogTableProps) { const applyFilters = () => { const filter: ActivityLogFilter = {}; if (filterAction) filter.action = filterAction as ActionType; + if (filterServerId) filter.server_id = filterServerId; if (filterStartDate) filter.start_date = new Date(filterStartDate).toISOString(); if (filterEndDate) filter.end_date = new Date(filterEndDate).toISOString(); setAppliedFilter(filter); @@ -96,6 +103,7 @@ export function ActivityLogTable({ serverId }: ActivityLogTableProps) { const clearFilters = () => { setFilterAction(''); + setFilterServerId(''); setFilterStartDate(''); setFilterEndDate(''); setAppliedFilter({}); @@ -112,9 +120,9 @@ export function ActivityLogTable({ serverId }: ActivityLogTableProps) { return (
-
+
- +
+ {servers && servers.length > 0 && ( +
+ + +
+ )}
- +
- +
- {error && ( -

{error}

- )} + {error &&

{error}

} -
+
{logs.length === 0 && !isLoading ? (
đź“‹
-

No activity logged yet.

+

No activity logged yet.

) : (
- - + - - + )} + - @@ -187,14 +215,17 @@ export function ActivityLogTable({ serverId }: ActivityLogTableProps) { {logs.map((log) => ( - - + + {!serverId && ( + + )} - + ))} @@ -212,12 +241,10 @@ export function ActivityLogTable({ serverId }: ActivityLogTableProps) { )} - {isLoading && ( -
Loading…
- )} + {isLoading &&
Loading…
} {hasMore && !isLoading && logs.length > 0 && ( -
+
diff --git a/src/lib/actions/activityLog.ts b/src/lib/actions/activityLog.ts index efb14e3..c3618f0 100644 --- a/src/lib/actions/activityLog.ts +++ b/src/lib/actions/activityLog.ts @@ -1,31 +1,15 @@ 'use server'; import { requireAuth } from '@/lib/auth/server'; -import { getActivityLog, getGlobalActivityLog } from '@/lib/api/server/activityLog'; +import { getActivityLog } from '@/lib/api/server/activityLog'; import type { ActivityLog, ActivityLogFilter } from '@/lib/schemas/activityLog'; export async function getActivityLogAction( - serverId: string, filter?: ActivityLogFilter ): Promise<{ success: true; data: ActivityLog[] } | { success: false; message: string }> { try { const session = await requireAuth(); - const data = await getActivityLog(session.token!, serverId, filter); - return { success: true, data }; - } catch (error) { - return { - success: false, - message: error instanceof Error ? error.message : 'Failed to fetch activity log' - }; - } -} - -export async function getGlobalActivityLogAction( - filter?: ActivityLogFilter -): Promise<{ success: true; data: ActivityLog[] } | { success: false; message: string }> { - try { - const session = await requireAuth(); - const data = await getGlobalActivityLog(session.token!, filter); + const data = await getActivityLog(session.token!, filter); return { success: true, data }; } catch (error) { return { diff --git a/src/lib/api/server/activityLog.ts b/src/lib/api/server/activityLog.ts index 9a5c629..ae7783b 100644 --- a/src/lib/api/server/activityLog.ts +++ b/src/lib/api/server/activityLog.ts @@ -1,5 +1,9 @@ import { fetchServerAPI } from './base'; -import { activityLogSchema, type ActivityLog, type ActivityLogFilter } from '@/lib/schemas/activityLog'; +import { + activityLogSchema, + type ActivityLog, + type ActivityLogFilter +} from '@/lib/schemas/activityLog'; function buildQuery(filter?: ActivityLogFilter): string { if (!filter) return ''; @@ -9,6 +13,7 @@ function buildQuery(filter?: ActivityLogFilter): string { if (filter.sort_by) params.set('sort_by', filter.sort_by); if (filter.sort_desc !== undefined) params.set('sort_desc', String(filter.sort_desc)); if (filter.user_id) params.set('user_id', filter.user_id); + if (filter.server_id) params.set('server_id', filter.server_id); if (filter.action) params.set('action', filter.action); if (filter.start_date) params.set('start_date', filter.start_date); if (filter.end_date) params.set('end_date', filter.end_date); @@ -17,23 +22,11 @@ function buildQuery(filter?: ActivityLogFilter): string { } export async function getActivityLog( - token: string, - serverId: string, - filter?: ActivityLogFilter -): Promise { - const query = buildQuery(filter); - const response = await fetchServerAPI( - `/server/${serverId}/activity-log${query}`, - token - ); - return activityLogSchema.array().parse(response.data); -} - -export async function getGlobalActivityLog( token: string, filter?: ActivityLogFilter ): Promise { const query = buildQuery(filter); const response = await fetchServerAPI(`/activity-log${query}`, token); + console.log(response.data); return activityLogSchema.array().parse(response.data); } diff --git a/src/lib/schemas/activityLog.ts b/src/lib/schemas/activityLog.ts index a692524..5a79371 100644 --- a/src/lib/schemas/activityLog.ts +++ b/src/lib/schemas/activityLog.ts @@ -10,9 +10,18 @@ export const actionTypeSchema = z.enum([ export type ActionType = z.infer; +// Minimal server shape embedded in activity log responses (avoids circular import with server.ts) +const embeddedServerSchema = z.object({ + id: z.string(), + name: z.string() +}).passthrough(); + +export type EmbeddedServer = z.infer; + export const activityLogSchema = z.object({ id: z.string(), serverId: z.string(), + server: embeddedServerSchema.optional(), userId: z.string(), username: z.string(), action: actionTypeSchema, @@ -36,6 +45,7 @@ export const activityLogFilterSchema = z.object({ sort_by: z.string().optional(), sort_desc: z.boolean().optional(), user_id: z.string().optional(), + server_id: z.string().optional(), action: actionTypeSchema.optional(), start_date: z.string().optional(), end_date: z.string().optional()
+
Time + User + {!serverId && ( + + Server + Action + Details
+ {formatDate(log.createdAt)} - {log.username} - {log.username} + {log.server?.name ?? log.serverId} + - {parseDetails(log.details)} - {parseDetails(log.details)}