upd: stack trace hide/show toggle and date format DD/MM/YYYY 24h
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,23 +1,23 @@
|
|||||||
import {
|
import {
|
||||||
Table,
|
Badge,
|
||||||
Badge,
|
|
||||||
Text,
|
|
||||||
Paper,
|
|
||||||
Group,
|
|
||||||
Drawer,
|
|
||||||
Stack,
|
|
||||||
Divider,
|
|
||||||
Code,
|
|
||||||
Button,
|
|
||||||
Box,
|
Box,
|
||||||
|
Button,
|
||||||
|
Code,
|
||||||
|
Divider,
|
||||||
|
Drawer,
|
||||||
|
Group,
|
||||||
|
Paper,
|
||||||
ScrollArea,
|
ScrollArea,
|
||||||
|
Stack,
|
||||||
|
Table,
|
||||||
|
Text,
|
||||||
Title
|
Title
|
||||||
} from '@mantine/core'
|
} from '@mantine/core'
|
||||||
import { useDisclosure } from '@mantine/hooks'
|
import { useDisclosure } from '@mantine/hooks'
|
||||||
import { useState } from 'react'
|
|
||||||
import { useQuery } from '@tanstack/react-query'
|
import { useQuery } from '@tanstack/react-query'
|
||||||
import { Link } from '@tanstack/react-router'
|
import { Link } from '@tanstack/react-router'
|
||||||
import { TbMessageReport, TbHistory, TbExternalLink, TbBug } from 'react-icons/tb'
|
import { useState } from 'react'
|
||||||
|
import { TbBug, TbExternalLink, TbHistory, TbMessageReport } from 'react-icons/tb'
|
||||||
|
|
||||||
export interface ErrorDataTableProps {
|
export interface ErrorDataTableProps {
|
||||||
appId?: string
|
appId?: string
|
||||||
@@ -26,6 +26,7 @@ export interface ErrorDataTableProps {
|
|||||||
export function ErrorDataTable({ appId }: ErrorDataTableProps) {
|
export function ErrorDataTable({ appId }: ErrorDataTableProps) {
|
||||||
const [opened, { open, close }] = useDisclosure(false)
|
const [opened, { open, close }] = useDisclosure(false)
|
||||||
const [selectedError, setSelectedError] = useState<any>(null)
|
const [selectedError, setSelectedError] = useState<any>(null)
|
||||||
|
const [showStackTrace, setShowStackTrace] = useState(false)
|
||||||
|
|
||||||
const { data: bugsData, isLoading } = useQuery({
|
const { data: bugsData, isLoading } = useQuery({
|
||||||
queryKey: ['bugs', appId],
|
queryKey: ['bugs', appId],
|
||||||
@@ -36,11 +37,12 @@ export function ErrorDataTable({ appId }: ErrorDataTableProps) {
|
|||||||
|
|
||||||
const handleRowClick = (error: any) => {
|
const handleRowClick = (error: any) => {
|
||||||
setSelectedError(error)
|
setSelectedError(error)
|
||||||
|
setShowStackTrace(false)
|
||||||
open()
|
open()
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSeverityColor = (sev: string) => {
|
const getSeverityColor = (sev: string) => {
|
||||||
switch(sev?.toUpperCase()) {
|
switch (sev?.toUpperCase()) {
|
||||||
case 'OPEN': return 'red'
|
case 'OPEN': return 'red'
|
||||||
case 'IN_PROGRESS': return 'orange'
|
case 'IN_PROGRESS': return 'orange'
|
||||||
case 'ON_HOLD': return 'yellow'
|
case 'ON_HOLD': return 'yellow'
|
||||||
@@ -90,10 +92,10 @@ export function ErrorDataTable({ appId }: ErrorDataTableProps) {
|
|||||||
</Table.Td>
|
</Table.Td>
|
||||||
</Table.Tr>
|
</Table.Tr>
|
||||||
) : bugs.map((error: any) => (
|
) : bugs.map((error: any) => (
|
||||||
<Table.Tr
|
<Table.Tr
|
||||||
key={error.id}
|
key={error.id}
|
||||||
onClick={() => handleRowClick(error)}
|
onClick={() => handleRowClick(error)}
|
||||||
style={{ cursor: 'pointer' }}
|
style={{ cursor: 'pointer' }}
|
||||||
>
|
>
|
||||||
<Table.Td px="xl">
|
<Table.Td px="xl">
|
||||||
<Text size="sm" fw={600} lineClamp={1}>{error.description}</Text>
|
<Text size="sm" fw={600} lineClamp={1}>{error.description}</Text>
|
||||||
@@ -107,7 +109,7 @@ export function ErrorDataTable({ appId }: ErrorDataTableProps) {
|
|||||||
<Table.Td>
|
<Table.Td>
|
||||||
<Group gap={6}>
|
<Group gap={6}>
|
||||||
<TbHistory size={12} color="gray" />
|
<TbHistory size={12} color="gray" />
|
||||||
<Text size="xs" c="dimmed">{new Date(error.createdAt).toLocaleString()}</Text>
|
<Text size="xs" c="dimmed">{new Date(error.createdAt).toLocaleString('en-GB', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false })}</Text>
|
||||||
</Group>
|
</Group>
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
<Table.Td pr="xl">
|
<Table.Td pr="xl">
|
||||||
@@ -146,8 +148,8 @@ export function ErrorDataTable({ appId }: ErrorDataTableProps) {
|
|||||||
|
|
||||||
<SimpleGrid cols={2} spacing="lg">
|
<SimpleGrid cols={2} spacing="lg">
|
||||||
<Box>
|
<Box>
|
||||||
<Text size="xs" fw={700} c="dimmed" mb={4}>REPORTER</Text>
|
<Text size="xs" fw={700} c="dimmed" mb={4}>SOURCE</Text>
|
||||||
<Text fw={600}>{selectedError.user?.name || selectedError.userId || 'System'}</Text>
|
<Text fw={600}>{selectedError.source}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Text size="xs" fw={700} c="dimmed" mb={4}>APP VERSION</Text>
|
<Text size="xs" fw={700} c="dimmed" mb={4}>APP VERSION</Text>
|
||||||
@@ -158,16 +160,23 @@ export function ErrorDataTable({ appId }: ErrorDataTableProps) {
|
|||||||
<Divider opacity={0.1} />
|
<Divider opacity={0.1} />
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text size="xs" fw={700} c="dimmed" mb="sm">STACK TRACE</Text>
|
<Group justify="space-between" mb="sm">
|
||||||
<Code block color="red" style={{ whiteSpace: 'pre-wrap', lineHeight: 1.6, border: '1px solid var(--mantine-color-default-border)' }}>
|
<Text size="xs" fw={700} c="dimmed">STACK TRACE</Text>
|
||||||
{selectedError.stackTrace}
|
<Button
|
||||||
</Code>
|
variant="subtle"
|
||||||
|
size="compact-xs"
|
||||||
|
color="gray"
|
||||||
|
onClick={() => setShowStackTrace((v) => !v)}
|
||||||
|
>
|
||||||
|
{showStackTrace ? 'Hide' : 'Show'}
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
{showStackTrace && (
|
||||||
|
<Code block color="red" style={{ whiteSpace: 'pre-wrap', lineHeight: 1.6, border: '1px solid var(--mantine-color-default-border)' }}>
|
||||||
|
{selectedError.stackTrace}
|
||||||
|
</Code>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Group justify="flex-end" mt="xl">
|
|
||||||
<Button variant="light" color="gray" onClick={close}>Dismiss</Button>
|
|
||||||
<Button variant="gradient" gradient={{ from: 'red', to: 'orange' }}>Assign Technician</Button>
|
|
||||||
</Group>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
</Drawer>
|
</Drawer>
|
||||||
|
|||||||
@@ -57,11 +57,16 @@ function AppErrorsPage() {
|
|||||||
|
|
||||||
|
|
||||||
const [showLogs, setShowLogs] = useState<Record<string, boolean>>({})
|
const [showLogs, setShowLogs] = useState<Record<string, boolean>>({})
|
||||||
|
const [showStackTrace, setShowStackTrace] = useState<Record<string, boolean>>({})
|
||||||
|
|
||||||
const toggleLogs = (bugId: string) => {
|
const toggleLogs = (bugId: string) => {
|
||||||
setShowLogs((prev) => ({ ...prev, [bugId]: !prev[bugId] }))
|
setShowLogs((prev) => ({ ...prev, [bugId]: !prev[bugId] }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toggleStackTrace = (bugId: string) => {
|
||||||
|
setShowStackTrace((prev) => ({ ...prev, [bugId]: !prev[bugId] }))
|
||||||
|
}
|
||||||
|
|
||||||
const { data, isLoading, refetch } = useQuery({
|
const { data, isLoading, refetch } = useQuery({
|
||||||
queryKey: ['bugs', { page, search, app, status }],
|
queryKey: ['bugs', { page, search, app, status }],
|
||||||
queryFn: () =>
|
queryFn: () =>
|
||||||
@@ -511,7 +516,7 @@ function AppErrorsPage() {
|
|||||||
</Group>
|
</Group>
|
||||||
<Group gap="md">
|
<Group gap="md">
|
||||||
<Text size="xs" c="dimmed">
|
<Text size="xs" c="dimmed">
|
||||||
{new Date(bug.createdAt).toLocaleString()} • {bug.appId?.toUpperCase()} • v{bug.affectedVersion}
|
{new Date(bug.createdAt).toLocaleString('en-GB', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false })} • {bug.appId?.toUpperCase()} • v{bug.affectedVersion}
|
||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -564,19 +569,31 @@ function AppErrorsPage() {
|
|||||||
{/* Stack Trace */}
|
{/* Stack Trace */}
|
||||||
{bug.stackTrace && (
|
{bug.stackTrace && (
|
||||||
<Box>
|
<Box>
|
||||||
<Text size="xs" fw={700} c="dimmed" mb={4}>STACK TRACE</Text>
|
<Group justify="space-between" mb={4}>
|
||||||
<Code
|
<Text size="xs" fw={700} c="dimmed">STACK TRACE</Text>
|
||||||
block
|
<Button
|
||||||
color="red"
|
variant="subtle"
|
||||||
style={{
|
size="compact-xs"
|
||||||
fontFamily: 'monospace',
|
color="gray"
|
||||||
whiteSpace: 'pre-wrap',
|
onClick={() => toggleStackTrace(bug.id)}
|
||||||
fontSize: '11px',
|
>
|
||||||
border: '1px solid var(--mantine-color-default-border)',
|
{showStackTrace[bug.id] ? 'Hide' : 'Show'}
|
||||||
}}
|
</Button>
|
||||||
>
|
</Group>
|
||||||
{bug.stackTrace}
|
<Collapse in={!!showStackTrace[bug.id]}>
|
||||||
</Code>
|
<Code
|
||||||
|
block
|
||||||
|
color="red"
|
||||||
|
style={{
|
||||||
|
fontFamily: 'monospace',
|
||||||
|
whiteSpace: 'pre-wrap',
|
||||||
|
fontSize: '11px',
|
||||||
|
border: '1px solid var(--mantine-color-default-border)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{bug.stackTrace}
|
||||||
|
</Code>
|
||||||
|
</Collapse>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -535,7 +535,7 @@ function ListErrorsPage() {
|
|||||||
</Group>
|
</Group>
|
||||||
<Group gap="md">
|
<Group gap="md">
|
||||||
<Text size="xs" c="dimmed">
|
<Text size="xs" c="dimmed">
|
||||||
{new Date(bug.createdAt).toLocaleString()} • {bug.appId?.toUpperCase()} • v{bug.affectedVersion}
|
{new Date(bug.createdAt).toLocaleString('en-GB', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false })} • {bug.appId?.toUpperCase()} • v{bug.affectedVersion}
|
||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
Reference in New Issue
Block a user