import { useParams } from 'common' import { BarChart, Shield } from 'lucide-react' import { useCallback, useMemo } from 'react' import { AiIconAnimation, Badge, Button, Card, CardContent, CardHeader, CardTitle, cn } from 'ui' import { Row } from 'ui-patterns' import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader' import { Markdown } from '../Markdown' import { LINTER_LEVELS } from '@/components/interfaces/Linter/Linter.constants' import { createLintSummaryPrompt } from '@/components/interfaces/Linter/Linter.utils' import { SIDEBAR_KEYS } from '@/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider' import type { AdvisorItem } from '@/components/ui/AdvisorPanel/AdvisorPanel.types' import { createAdvisorLintItems, getAdvisorItemDisplayTitle, MAX_HOMEPAGE_ADVISOR_ITEMS, severityBadgeVariants, severityColorClasses, sortAdvisorItems, } from '@/components/ui/AdvisorPanel/AdvisorPanel.utils' import { useAdvisorSignals } from '@/components/ui/AdvisorPanel/useAdvisorSignals' import { AiAssistantDropdown } from '@/components/ui/AiAssistantDropdown' import { 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' export const AdvisorSection = ({ showEmptyState = false }: { showEmptyState?: boolean }) => { const { ref: projectRef } = useParams() const track = useTrack() const snap = useAiAssistantStateSnapshot() const { openSidebar } = useSidebarManagerSnapshot() const { setSelectedItem } = useAdvisorStateSnapshot() const { data: lints, isLoading: isLoadingLints } = useProjectLintsQuery( { projectRef }, { enabled: !showEmptyState } ) const { data: signalItems } = useAdvisorSignals({ projectRef, enabled: !showEmptyState }) const advisorItems = useMemo(() => { const criticalLintItems = createAdvisorLintItems(lints).filter( (item) => item.source === 'lint' && item.original.level === LINTER_LEVELS.ERROR ) return sortAdvisorItems([...criticalLintItems, ...signalItems]) }, [lints, signalItems]) const visibleAdvisorItems = useMemo( () => advisorItems.slice(0, MAX_HOMEPAGE_ADVISOR_ITEMS), [advisorItems] ) const totalIssues = advisorItems.length const hiddenIssuesCount = totalIssues - visibleAdvisorItems.length const titleContent = useMemo(() => { if (totalIssues === 0) return

Advisor found no issues

const issuesText = totalIssues === 1 ? 'issue' : 'issues' const numberDisplay = totalIssues.toString() return (

Advisor found {numberDisplay} {issuesText}

) }, [totalIssues]) const handleAskAssistant = useCallback(() => { openSidebar(SIDEBAR_KEYS.AI_ASSISTANT) track('advisor_assistant_button_clicked', { origin: 'homepage', issuesCount: totalIssues, }) }, [track, openSidebar, totalIssues]) const handleCardClick = useCallback( (item: AdvisorItem) => { setSelectedItem(item.id, item.source) openSidebar(SIDEBAR_KEYS.ADVISOR_PANEL) const advisorCategory = item.source === 'lint' ? item.original.categories.includes('SECURITY') ? 'SECURITY' : item.original.categories.includes('PERFORMANCE') ? 'PERFORMANCE' : undefined : item.source === 'signal' ? 'SECURITY' : undefined const advisorType = item.source === 'signal' ? item.type : item.source === 'lint' ? item.original.name : item.title const advisorLevel = item.source === 'lint' ? item.original.level : undefined track('advisor_detail_opened', { origin: 'homepage', advisorSource: item.source, advisorCategory, advisorType, advisorLevel, }) }, [track, setSelectedItem, openSidebar] ) if (showEmptyState) { return } // [Joshen] Note that we're intentionally (for now) not waiting for advisor signals to load // render main content as long as the main lints have been fetched return (
{isLoadingLints ? ( ) : (
{titleContent}
)} {isLoadingLints ? (
) : visibleAdvisorItems.length > 0 ? ( <> {visibleAdvisorItems.map((item) => { const isLint = item.source === 'lint' const categoryLabel = item.tab === 'performance' ? 'PERFORMANCE' : 'SECURITY' const title = getAdvisorItemDisplayTitle(item) const description = item.source === 'signal' ? item.summary : isLint ? item.original.detail : '' const cardClasses = item.severity === 'critical' ? 'bg-destructive-200 border-destructive-400' : item.severity === 'warning' ? 'border-warning-400' : '' return ( { handleCardClick(item) }} >
{item.tab === 'security' ? ( ) : ( )} {categoryLabel}
{item.severity.toUpperCase()} {isLint && (
{ e.stopPropagation() e.preventDefault() }} > createLintSummaryPrompt(item.original)} onOpenAssistant={() => { openSidebar(SIDEBAR_KEYS.AI_ASSISTANT) snap.newChat({ name: 'Summarise lint', initialInput: createLintSummaryPrompt(item.original), }) track('advisor_assistant_button_clicked', { origin: 'homepage', advisorCategory: item.original.categories[0], advisorType: item.original.name, advisorLevel: item.original.level, }) }} telemetrySource="advisor_section" type="text" className="w-7 h-7" />
)}

{title}

{description && description.replace(/\\`/g, '`')}
) })}
{hiddenIssuesCount > 0 && (
)} ) : ( )}
) } function EmptyState() { return (

No security or performance issues found

) }