import { useFlag, useParams } from 'common' import { Shield } from 'lucide-react' import { useCallback, useMemo } from 'react' import { AiIconAnimation, Badge, Button, Card, CardContent, Tooltip, TooltipContent, TooltipTrigger, } from 'ui' import { Row } from 'ui-patterns/Row' import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader' import { Markdown } from '../Markdown' import { HomeCard } from './HomeCard' 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 { advisorCategoryIcons, createAdvisorLintItems, getAdvisorItemDisplayTitle, getAdvisorItemTelemetryCategory, MAX_HOMEPAGE_ADVISOR_ITEMS, severityBadgeVariants, severityColorClasses, sortAdvisorItems, } from '@/components/ui/AdvisorPanel/AdvisorPanel.utils' import { useAdvisorSignals } from '@/components/ui/AdvisorPanel/useAdvisorSignals' import { ButtonTooltip } from '@/components/ui/ButtonTooltip' import CopyButton from '@/components/ui/CopyButton' import { useProjectHealthLintsQuery } from '@/data/lint/health-lints-query' 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 isHealthAdvisorEnabled = useFlag('healthAdvisor') const isHealthAdvisorInHomepageEnabled = useFlag('healthAdvisorInHomepage') const canShowHealthAdvisor = isHealthAdvisorEnabled && isHealthAdvisorInHomepageEnabled const track = useTrack() const snap = useAiAssistantStateSnapshot() const { openSidebar } = useSidebarManagerSnapshot() const { setSelectedItem } = useAdvisorStateSnapshot() const { data: lints, isLoading: isLoadingLints } = useProjectLintsQuery( { projectRef }, { enabled: !showEmptyState } ) const { data: healthLints } = useProjectHealthLintsQuery( { projectRef }, { enabled: !showEmptyState && canShowHealthAdvisor } ) const { data: signalItems } = useAdvisorSignals({ projectRef, enabled: !showEmptyState }) const advisorItems = useMemo(() => { const criticalLintItems = createAdvisorLintItems([ ...(lints ?? []), ...(canShowHealthAdvisor ? (healthLints ?? []) : []), ]).filter((item) => item.source === 'lint' && item.original.level === LINTER_LEVELS.ERROR) return sortAdvisorItems([...criticalLintItems, ...signalItems]) }, [lints, healthLints, signalItems, canShowHealthAdvisor]) 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 = getAdvisorItemTelemetryCategory(item) 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' // Only security, performance and health items reach the homepage row const categoryLabel = item.category.toUpperCase() const CategoryIcon = advisorCategoryIcons[item.category] 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)} icon={ } label={categoryLabel} title={title} description={ description && {description.replace(/\\`/g, '`')} } actions={ <> {item.severity.toUpperCase()} {isLint && ( <> } aria-label="Ask Assistant" tooltip={{ content: { text: 'Ask Assistant to fix this issue' } }} onClick={() => { openSidebar(SIDEBAR_KEYS.AI_ASSISTANT) snap.newChat({ name: 'Summarise lint', initialInput: createLintSummaryPrompt(item.original), }) track('advisor_assistant_button_clicked', { origin: 'homepage', advisorCategory: getAdvisorItemTelemetryCategory(item), advisorType: item.original.name, advisorLevel: item.original.level, }) }} /> createLintSummaryPrompt(item.original)} onClick={() => track('ai_prompt_copied', { source: 'advisor_section' }) } /> Copy prompt )} } /> ) })} {hiddenIssuesCount > 0 && (
)} ) : ( )}
) } function EmptyState({ canShowHealthAdvisor }: { canShowHealthAdvisor: boolean }) { return (

{canShowHealthAdvisor ? 'No security, performance or health issues found' : 'No security or performance issues found'}

) }