import { useEffect, useState } from 'react' import { toast } from 'sonner' import { Button, cn, copyToClipboard, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, Separator, } from 'ui' import { TimestampInfo } from 'ui-patterns' import { ErrorCodeDialog } from '../ErrorCodeDialog' import type { LogSearchCallback, PreviewLogData } from '../Logs.types' import { ResponseCodeFormatter } from '../LogsFormatters' import { ErrorCodeTooltip } from '@/components/ui/ErrorCodeTooltip/ErrorCodeTooltip' import { Service } from '@/data/graphql/graphql' import { useLogsUrlState } from '@/hooks/analytics/useLogsUrlState' const LogRowCodeBlock = ({ value, className }: { value: string; className?: string }) => (
    {typeof value === 'string' ? value : JSON.stringify(value, null, 2)}
  
) const LogRowSeparator = () => const PropertyRow = ({ keyName, value, dataTestId, path, }: { keyName: string value: any dataTestId?: string path?: string }) => { const { setSearch } = useLogsUrlState() const [showErrorInfo, setShowErrorInfo] = useState(false) const service = path?.startsWith('/auth/') ? Service.Auth : undefined const handleSearch: LogSearchCallback = async (_event: string, { query }: { query?: string }) => { setSearch(query || '') } const isTimestamp = keyName === 'timestamp' || keyName === 'created_at' || keyName === 'updated_at' const isObject = typeof value === 'object' && value !== null const isStatus = keyName === 'status' || keyName === 'status_code' const isMethod = keyName === 'method' const isSearch = keyName === 'search' const isUserAgent = keyName === 'user_agent' const isEventMessage = keyName === 'event_message' const isPath = keyName === 'path' const isErrorCode = keyName === 'error_code' function getSearchPairs() { if (isSearch && typeof value === 'string') { const str = value.startsWith('?') ? value.slice(1) : value return str.split('&').filter(Boolean) } return [] } const storageKey = `log-viewer-expanded-${keyName}` const [isExpanded, setIsExpanded] = useState(() => { try { // Storing in local storage so users dont have to click expand every time they change selected log return JSON.parse(localStorage.getItem(storageKey) ?? 'false') } catch (_) { return false } }) const [isCopied, setIsCopied] = useState(false) useEffect(() => { localStorage.setItem(storageKey, JSON.stringify(isExpanded)) }, [isExpanded, storageKey]) const handleCopy = () => { copyToClipboard(String(value), () => { setIsCopied(true) toast.success('Copied to clipboard') }) setTimeout(() => { setIsCopied(false) }, 1000) } if (isObject || isEventMessage) { return ( <>

{keyName}

{!isEventMessage && ( )}
) } return ( <>

{keyName}

{isExpanded ? ( ) : isTimestamp ? ( ) : isStatus ? (
) : isMethod ? (
) : isErrorCode ? (
{value}
) : (
{value}
)}
{keyName === 'error_code' && ( { setShowErrorInfo(true) }} > More information )} Copy {keyName} {!isObject && ( { setIsExpanded(!isExpanded) }} > {isExpanded ? 'Collapse' : 'Expand'} value )} {(isMethod || isUserAgent || isStatus || isPath) && ( { handleSearch('search-input-change', { query: value }) }} > Search by {keyName} )} {isSearch ? getSearchPairs().map((pair) => ( { handleSearch('search-input-change', { query: pair }) }} > Search by {pair} )) : null}
{keyName === 'error_code' && ( )} ) } const DefaultPreviewSelectionRenderer = ({ log }: { log: PreviewLogData }) => { const { timestamp, event_message, metadata, id, status, ...rest } = log const path = typeof log.path === 'string' ? log.path : undefined const log_file = log?.metadata?.[0]?.log_file return (
{log?.id && ( )} {log?.status && } {log?.timestamp && ( )} {Object.entries(rest).map(([key, value]) => { return })} {log?.event_message && ( )} {!!log_file && } {log?.metadata && }
) } export default DefaultPreviewSelectionRenderer