import { useState, useMemo } from "react"; import { Trans, Plural, useLingui } from "@lingui/react/macro"; import { Alert, Code, Container, Group, Stack, Text } from "@mantine/core"; import { CheckIcon, XIcon } from "@phosphor-icons/react"; import { Activity, ActivitySearchParams } from "../types"; import { useActivities } from "../queries"; import { usePlayers } from "@/features/players/queries"; import { useSheet } from "@/hooks/use-sheet"; import { DetailSheet, PaginatedList, SearchFilterBar, TelemetryListItem, } from "@/features/telemetry/components/shared"; const SLOW_THRESHOLD_MS = 1000; export const ActivitiesTable = () => { const { t, i18n } = useLingui(); const [page, setPage] = useState(1); const [search, setSearch] = useState(""); const [successFilter, setSuccessFilter] = useState(null); const [playerFilter, setPlayerFilter] = useState(null); const [slowOnly, setSlowOnly] = useState(false); const [sortBy, setSortBy] = useState("-created"); const [selectedActivity, setSelectedActivity] = useState(null); const { isOpen: detailsOpened, open: openDetails, close: closeDetails } = useSheet(); const { data: players } = usePlayers(); const searchParams: ActivitySearchParams = useMemo( () => ({ page, perPage: 100, name: search || undefined, success: successFilter === "success" ? true : successFilter === "failure" ? false : undefined, player: playerFilter || undefined, sortBy, }), [page, search, successFilter, playerFilter, sortBy] ); const { data: result } = useActivities(searchParams); const items = useMemo( () => (slowOnly ? result.items.filter((a) => a.duration > SLOW_THRESHOLD_MS) : result.items), [result.items, slowOnly] ); const playerName = (activity: Activity) => typeof activity.player === "object" && activity.player ? `${activity.player.first_name} ${activity.player.last_name}` : t`System`; const handleSort = (field: string) => { setSortBy((prev) => { if (prev === field) return `-${field}`; if (prev === `-${field}`) return field; return `-${field}`; }); }; const handleActivityClick = (activity: Activity) => { setSelectedActivity(activity); openDetails(); }; const handleCloseDetails = () => { setSelectedActivity(null); closeDetails(); }; return ( { setSearch(value); setPage(1); }} searchPlaceholder={t`serverFn name`} filters={[ { placeholder: t`Status`, value: successFilter, onChange: (value) => { setSuccessFilter(value); setPage(1); }, data: [ { value: "all", label: t`All` }, { value: "success", label: t`Success` }, { value: "failure", label: t`Failure` }, ], }, { placeholder: t`Player`, value: playerFilter, onChange: (value) => { setPlayerFilter(value); setPage(1); }, data: players.map((player) => ({ value: player.id, label: `${player.first_name} ${player.last_name}`, })), searchable: true, }, ]} chips={[ { label: t`Slow >1s (this page)`, checked: slowOnly, onChange: setSlowOnly, }, ]} sortFields={[ { field: "created", label: Date }, { field: "duration", label: Duration }, ]} sortBy={sortBy} onSort={handleSort} summary={ } /> activity.id} empty={t`No Activities Found`} page={page} totalPages={result.totalPages} onPageChange={setPage} renderItem={(activity) => ( ) : ( ) } meta={[ playerName(activity), {activity.duration}ms, new Date(activity.created).toLocaleString(i18n.locale), ]} error={activity.error} onClick={() => handleActivityClick(activity)} /> )} /> Function Name, value: selectedActivity.name }, { label: Status, value: ( {selectedActivity.success ? ( <> Success ) : ( <> Failed )} ), }, { label: Player, value: playerName(selectedActivity) }, { label: Duration, value: ( {selectedActivity.duration}ms ), }, { label: Created, value: new Date(selectedActivity.created).toLocaleString(i18n.locale), }, ...(selectedActivity.user_agent ? [{ label: User Agent, value: selectedActivity.user_agent }] : []), ...(selectedActivity.error ? [ { label: Error Message, value: ( {selectedActivity.error} ), }, ] : []), ...(selectedActivity.arguments ? [ { label: Arguments, value: ( {JSON.stringify(selectedActivity.arguments, null, 2)} ), }, ] : []), ] : [] } /> ); };