import { useMemo, useState } from "react"; import { useParams } from "react-router"; import type { EventEnvelope } from "@qltysh/fabro-api-client"; import { DebugEventDetailsPanel, DebugEventRow, EventSearchInput, MultiSelectFilter, debugCategory, debugCategoryLabel, } from "../components/event-debug"; import { StageSidebar } from "../components/stage-sidebar"; import { EmptyState, ErrorState, LoadingState } from "../components/state"; import { useRun, useRunEventsList, useRunStages } from "../lib/queries"; import { mapRunStagesToSidebarStages } from "../lib/stage-sidebar"; export const handle = { wide: true, fullHeight: true }; export default function RunEvents() { const { id } = useParams(); const runQuery = useRun(id); const stagesQuery = useRunStages(id); const eventsQuery = useRunEventsList(id); const stages = useMemo( () => mapRunStagesToSidebarStages(stagesQuery.data), [stagesQuery.data], ); return (
void eventsQuery.mutate()} runStart={runQuery.data?.start_time ?? runQuery.data?.created_at} />
); } function EventsView({ events, error, onRetry, runStart, }: { events: EventEnvelope[] | undefined; error: unknown; onRetry: () => void; runStart: string | undefined; }) { const [openSeq, setOpenSeq] = useState(null); const [selectedCategories, setSelectedCategories] = useState([]); const [search, setSearch] = useState(""); const all = events ?? []; const availableCategories = useMemo(() => { const set = new Set(); for (const event of all) { if (event.event) set.add(debugCategory(event.event)); } return Array.from(set).sort(); }, [all]); const filtered = useMemo(() => { const useCategoryFilter = selectedCategories.length > 0; const cats = new Set(selectedCategories); const needle = search.toLowerCase(); return all.filter((event) => { const name = event.event ?? ""; if (useCategoryFilter && !cats.has(debugCategory(name))) return false; if (needle) { const blob = `${name} ${JSON.stringify(event.properties ?? {})}`.toLowerCase(); if (!blob.includes(needle)) return false; } return true; }); }, [all, selectedCategories, search]); const openEvent = useMemo( () => (openSeq != null ? all.find((e) => e.seq === openSeq) ?? null : null), [all, openSeq], ); const allCategoriesSelected = selectedCategories.length === 0 || selectedCategories.length === availableCategories.length; const isFiltering = !allCategoriesSelected || search.length > 0; function clearFilters() { setSelectedCategories([]); setSearch(""); } if (error) { return (
); } if (events === undefined) { return (
); } return ( <>
selected={selectedCategories} options={availableCategories} labelOf={debugCategoryLabel} onChange={setSelectedCategories} emptyMeansAll /> {isFiltering && ( )}
{all.length > 0 && ( {isFiltering ? `${filtered.length.toLocaleString()} of ${all.length.toLocaleString()} events` : `${all.length.toLocaleString()} events`} )}
{all.length === 0 ? (
) : filtered.length === 0 ? (
No events match these filters.
) : ( filtered.map((event) => ( setOpenSeq(event.seq)} /> )) )}
setOpenSeq(null)} /> ); } function errorMessage(error: unknown): string | undefined { return error instanceof Error ? error.message : undefined; }