import { BookOpen, Check, ExternalLink, Eye } from 'lucide-react' import { useRouter } from 'next/router' import { Fragment, useMemo } from 'react' import { Badge, Button, Card, cn, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from 'ui' import { PageContainer } from 'ui-patterns/PageContainer' import { PageSection, PageSectionAside, PageSectionContent, PageSectionMeta, PageSectionSummary, PageSectionTitle, } from 'ui-patterns/PageSection' import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader' import { buildGroupAssistantPrompt, buildTroubleshootingDocsUrl, formatLogTimestamp, formatSingleLineMessage, getDisplayErrorMessage, getFunctionRuntimeLogsSql, getRecentErrorGroups, getRecentErrorGroupsBase, getRecentErrorInvocationsSql, getRelatedExecutionIds, getSinceLastDeployInvocationCount, getSinceLastDeployInvocationCountSql, getSinceLastDeployInvocationPhrase, getSinceLastDeployLogRange, getStatusBadgeVariant, toAlertError, type RecentErrorGroup, } from './EdgeFunctionRecentErrors.utils' import { SIDEBAR_KEYS } from '@/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider' import { AiAssistantDropdown } from '@/components/ui/AiAssistantDropdown' import AlertError from '@/components/ui/AlertError' import useLogsQuery from '@/hooks/analytics/useLogsQuery' import { useAiAssistantStateSnapshot } from '@/state/ai-assistant-state' import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state' interface EdgeFunctionRecentErrorsProps { functionId?: string functionSlug?: string projectRef?: string updatedAt?: string | number } export const EdgeFunctionRecentErrors = ({ functionId, functionSlug, projectRef, updatedAt, }: EdgeFunctionRecentErrorsProps) => { const router = useRouter() const { openSidebar } = useSidebarManagerSnapshot() const aiAssistant = useAiAssistantStateSnapshot() const { isoTimestampStart, isoTimestampEnd } = useMemo( () => getSinceLastDeployLogRange(updatedAt), [updatedAt] ) const emptyStateFallback = 'Runtime errors since the last deploy will appear here when this function returns a 5xx response.' const isQueryEnabled = Boolean(projectRef && functionId && isoTimestampStart) const recentErrorInvocationsSql = useMemo( () => getRecentErrorInvocationsSql(functionId), [functionId] ) const sinceLastDeployInvocationCountSql = useMemo( () => getSinceLastDeployInvocationCountSql(functionId), [functionId] ) const { logData: recentErrorInvocations, isLoading: isLoadingRecentErrorInvocations, error: recentErrorInvocationsError, } = useLogsQuery( projectRef as string, { sql: recentErrorInvocationsSql, iso_timestamp_start: isoTimestampStart, iso_timestamp_end: isoTimestampEnd, }, isQueryEnabled ) const recentErrorGroupsBase = useMemo( () => getRecentErrorGroupsBase(recentErrorInvocations), [recentErrorInvocations] ) const { logData: sinceLastDeployInvocationCountRows, isLoading: isLoadingSinceLastDeployInvocationCount, error: sinceLastDeployInvocationCountError, } = useLogsQuery( projectRef as string, { sql: sinceLastDeployInvocationCountSql, iso_timestamp_start: isoTimestampStart, iso_timestamp_end: isoTimestampEnd, }, Boolean(projectRef && sinceLastDeployInvocationCountSql && isoTimestampStart) ) const relatedExecutionIds = useMemo( () => getRelatedExecutionIds(recentErrorGroupsBase), [recentErrorGroupsBase] ) const functionRuntimeLogsSql = useMemo( () => getFunctionRuntimeLogsSql({ functionId, executionIds: relatedExecutionIds }), [functionId, relatedExecutionIds] ) const { logData: functionRuntimeLogs, isLoading: isLoadingFunctionRuntimeLogs, error: functionRuntimeLogsError, } = useLogsQuery( projectRef as string, { sql: functionRuntimeLogsSql, iso_timestamp_start: isoTimestampStart, iso_timestamp_end: isoTimestampEnd, }, Boolean(projectRef && functionRuntimeLogsSql && isoTimestampStart) ) const queryError = toAlertError(recentErrorInvocationsError) ?? toAlertError(functionRuntimeLogsError) const recentErrorGroups = useMemo( () => getRecentErrorGroups({ recentErrorGroupsBase, functionRuntimeLogs }), [functionRuntimeLogs, recentErrorGroupsBase] ) const sinceLastDeployInvocationCount = useMemo( () => getSinceLastDeployInvocationCount(sinceLastDeployInvocationCountRows), [sinceLastDeployInvocationCountRows] ) const emptyStateMessage = useMemo(() => { if (!isoTimestampStart || sinceLastDeployInvocationCountError) return emptyStateFallback const verb = sinceLastDeployInvocationCount === 1 ? 'has' : 'have' const invocationPhrase = getSinceLastDeployInvocationPhrase(sinceLastDeployInvocationCount) return ( <> There {verb} been {invocationPhrase} since last deploy and no errors. ) }, [ emptyStateFallback, isoTimestampStart, sinceLastDeployInvocationCount, sinceLastDeployInvocationCountError, ]) const emptyStateIcon = isoTimestampStart && !sinceLastDeployInvocationCountError ? ( sinceLastDeployInvocationCount > 0 ? (