import { useParams } from 'common' import { Activity, ExternalLink, Shield } from 'lucide-react' import Link from 'next/link' import { useCallback, useMemo, useState } from 'react' import { Card, CardContent, CardHeader, CardTitle, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs_Shadcn_ as Tabs, TabsContent_Shadcn_ as TabsContent, TabsList_Shadcn_ as TabsList, TabsTrigger_Shadcn_ as TabsTrigger, } from 'ui' import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader' import { useQueryPerformanceQuery } from '../QueryPerformance/useQueryPerformanceQuery' import { LINTER_LEVELS } from '@/components/interfaces/Linter/Linter.constants' import { createLintSummaryPrompt, EntityTypeIcon, } from '@/components/interfaces/Linter/Linter.utils' import { SIDEBAR_KEYS } from '@/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider' import { AiAssistantDropdown } from '@/components/ui/AiAssistantDropdown' import { ButtonTooltip } from '@/components/ui/ButtonTooltip' import { Lint, useProjectLintsQuery } from '@/data/lint/lint-query' import { useTrack } from '@/lib/telemetry/track' import { useAdvisorStateSnapshot } from '@/state/advisor-state' import { useAiAssistantStateSnapshot } from '@/state/ai-assistant-state' import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state' interface SlowQuery { rolname: string mean_time: number calls: number query: string } export const AdvisorWidget = () => { const { ref: projectRef } = useParams() const [selectedTab, setSelectedTab] = useState<'security' | 'performance'>('security') const { data: lints, isPending: isLoadingLints } = useProjectLintsQuery({ projectRef }) const { data: slowestQueriesData, isLoading: isLoadingSlowestQueries } = useQueryPerformanceQuery( { preset: 'slowestExecutionTime' } ) const snap = useAiAssistantStateSnapshot() const { openSidebar } = useSidebarManagerSnapshot() const { setSelectedItem } = useAdvisorStateSnapshot() const track = useTrack() const securityLints = useMemo( () => (lints ?? []).filter((lint: Lint) => lint.categories.includes('SECURITY')), [lints] ) const performanceLints = useMemo( () => (lints ?? []).filter((lint: Lint) => lint.categories.includes('PERFORMANCE')), [lints] ) const securityErrorCount = securityLints.filter( (lint: Lint) => lint.level === LINTER_LEVELS.ERROR ).length const securityWarningCount = securityLints.filter( (lint: Lint) => lint.level === LINTER_LEVELS.WARN ).length const performanceErrorCount = performanceLints.filter( (lint: Lint) => lint.level === LINTER_LEVELS.ERROR ).length const performanceWarningCount = performanceLints.filter( (lint: Lint) => lint.level === LINTER_LEVELS.WARN ).length const top5SlowestQueries = useMemo( () => ((slowestQueriesData ?? []) as SlowQuery[]).slice(0, 5), [slowestQueriesData] ) const handleLintClick = useCallback( (lint: Lint) => { setSelectedItem(lint.cache_key, 'lint') openSidebar(SIDEBAR_KEYS.ADVISOR_PANEL) }, [setSelectedItem, openSidebar] ) const totalIssues = securityErrorCount + securityWarningCount + performanceErrorCount + performanceWarningCount const hasErrors = securityErrorCount > 0 || performanceErrorCount > 0 const hasWarnings = securityWarningCount > 0 || performanceWarningCount > 0 let titleContent: React.ReactNode if (totalIssues === 0) { titleContent =

No issues available

} else { const issuesText = totalIssues === 1 ? 'issue' : 'issues' const numberDisplay = totalIssues.toString() let attentionClassName = '' if (hasErrors) { attentionClassName = 'text-destructive' } else if (hasWarnings) { attentionClassName = 'text-warning' } titleContent = (

{numberDisplay} {issuesText} need {totalIssues === 1 ? 's' : ''} attention

) } const renderLintTabContent = ( title: string, lints: Lint[], errorCount: number, warningCount: number, isLoading: boolean ) => { const topIssues = lints .filter((lint) => lint.level === LINTER_LEVELS.ERROR || lint.level === LINTER_LEVELS.WARN) .sort((a, _b) => (a.level === LINTER_LEVELS.ERROR ? -1 : 1)) return (
{isLoading && (
)} {!isLoading && (errorCount > 0 || warningCount > 0) && ( )} {!isLoading && errorCount === 0 && warningCount === 0 && (

No {title.toLowerCase()} issues found

)}
) } return (
{isLoadingLints ? ( ) : (
{titleContent}
)}
setSelectedTab('security')} className="flex items-center gap-2 text-xs py-3 border-b font-mono uppercase" > Security{' '} {securityErrorCount + securityWarningCount > 0 && (
{securityErrorCount + securityWarningCount}
)}
setSelectedTab('performance')} className="flex items-center gap-2 text-xs py-3 border-b font-mono uppercase" > Performance{' '} {performanceErrorCount + performanceWarningCount > 0 && (
{performanceErrorCount + performanceWarningCount}
)}
} tooltip={{ content: { side: 'bottom', text: `Open ${selectedTab} Advisor`, className: 'capitalize', }, }} >
{renderLintTabContent( 'Security', securityLints, securityErrorCount, securityWarningCount, isLoadingLints )} {renderLintTabContent( 'Performance', performanceLints, performanceErrorCount, performanceWarningCount, isLoadingLints )}
Slow Queries } tooltip={{ content: { side: 'bottom', text: `Open Query Performance Advisor`, }, }} > {isLoadingSlowestQueries ? (
) : top5SlowestQueries.length === 0 ? (

No slow queries found in the selected period

) : ( Query Avg time Calls {/* Added explicit types for map parameters */} {top5SlowestQueries.map((query: SlowQuery, i: number) => ( {query.query} {typeof query.mean_time === 'number' ? `${(query.mean_time / 1000).toFixed(2)}s` : 'N/A'} {query.calls} ))}
)}
) }