Files
flxn-app/src/features/telemetry/components/error-browser/error-group-row.tsx
T
kyle fd0489a22f refactor(telemetry): chart scale labels, calmer vitals and error styling, usage-first tabs
- sparklines get start/end date and max-value footers
- vitals rating shown by value color instead of badges
- error rows use plain counts, subtle resolve button, terse empty state
- telemetry tab order: usage, players, functions, events, errors; usage is default
2026-08-25 22:35:16 -07:00

112 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState } from "react";
import { Trans, useLingui } from "@lingui/react/macro";
import {
Box,
Button,
Code,
Collapse,
Group,
Stack,
Text,
UnstyledButton,
} from "@mantine/core";
import { useQueryClient } from "@tanstack/react-query";
import { useServerMutation } from "@/lib/tanstack-query/hooks";
import { resolveClientErrorGroup } from "../../server";
import { telemetryKeys } from "../../queries";
import type { ClientErrorGroup } from "../../types";
import { RelativeTime } from "../shared";
export const ErrorGroupRow = ({ group }: { group: ClientErrorGroup }) => {
const { t } = useLingui();
const [expanded, setExpanded] = useState(false);
const queryClient = useQueryClient();
const resolveMutation = useServerMutation({
mutationFn: (variables: { groupHash: string; resolved: boolean }) =>
resolveClientErrorGroup({ data: variables }),
successMessage: group.resolved ? t`Error group reopened` : t`Error group resolved`,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: telemetryKeys.all });
},
});
return (
<Box>
<UnstyledButton
w="100%"
p="md"
onClick={() => setExpanded((prev) => !prev)}
style={{ borderRadius: 0 }}
>
<Stack gap={4}>
<Group gap="xs" wrap="nowrap">
<Text
size="sm"
fw={700}
c={group.resolved ? "dimmed" : "red"}
style={{ flexShrink: 0, fontVariantNumeric: "tabular-nums" }}
>
{group.count.toLocaleString()}×
</Text>
<Text size="sm" fw={600} lineClamp={2} style={{ minWidth: 0 }}>
{group.sample.message}
</Text>
</Group>
<Group gap="md">
{group.sample.source && (
<Text size="xs" c="dimmed">
{group.sample.source}
</Text>
)}
<Text size="xs" c="dimmed">
<RelativeTime date={group.lastSeen} />
</Text>
{group.resolved && (
<Text size="xs" c="dimmed">
<Trans>Resolved</Trans>
</Text>
)}
</Group>
</Stack>
</UnstyledButton>
<Collapse in={expanded} transitionDuration={200}>
<Stack gap="sm" px="md" pb="md">
{group.sample.path && (
<Text size="xs" c="dimmed">
{group.sample.path}
</Text>
)}
{group.sample.stack && (
<Code
block
style={{ fontSize: "11px", maxHeight: 240, overflow: "auto" }}
>
{group.sample.stack}
</Code>
)}
<Group justify="flex-end">
<Button
size="xs"
variant="subtle"
color={group.resolved ? "yellow" : "green"}
loading={resolveMutation.isPending}
onClick={() =>
resolveMutation.mutate({
groupHash: group.group_hash,
resolved: !group.resolved,
})
}
>
{group.resolved ? <Trans>Reopen</Trans> : <Trans>Mark resolved</Trans>}
</Button>
</Group>
</Stack>
</Collapse>
</Box>
);
};
export default ErrorGroupRow;