import { AlertTriangle, ChevronRight, Inbox } from 'lucide-react'
import { Badge, Button, cn } from 'ui'
import { GenericSkeletonLoader } from 'ui-patterns'
import type { AdvisorItem } from './AdvisorPanel.types'
import {
formatItemDate,
getAdvisorItemSecondaryText,
getAdvisorPanelItemDisplayTitle,
severityBadgeVariants,
severityColorClasses,
severityLabels,
tabIconMap,
} from './AdvisorPanel.utils'
import { EmptyAdvisor } from './EmptyAdvisor'
import type { Notification } from '@/data/notifications/notifications-v2-query'
import type { AdvisorSeverity, AdvisorTab } from '@/state/advisor-state'
const NoProjectNotice = () => {
return (
Project required
Select a project to view security and performance advisories
)
}
interface AdvisorPanelBodyProps {
isLoading: boolean
isError: boolean
filteredItems: AdvisorItem[]
activeTab: AdvisorTab
severityFilters: AdvisorSeverity[]
onItemClick: (item: AdvisorItem) => void
onClearFilters: () => void
hiddenItemsCount: number
hasAnyFilters: boolean
hasProjectRef?: boolean
projectNameByRef?: ReadonlyMap
}
export const AdvisorPanelBody = ({
isLoading,
isError,
filteredItems,
activeTab,
severityFilters,
onItemClick,
onClearFilters,
hiddenItemsCount,
hasAnyFilters,
hasProjectRef = true,
projectNameByRef,
}: AdvisorPanelBodyProps) => {
// Show notice if no project ref and trying to view project-specific tabs
if (!hasProjectRef && activeTab !== 'messages' && activeTab !== 'all') {
return
}
if (isLoading) {
return (
)
}
if (isError) {
return (
Error loading advisories
Please try again later.
)
}
if (filteredItems.length === 0) {
return (
)
}
return (
<>
{filteredItems.map((item) => {
const SeverityIcon = tabIconMap[item.tab as Exclude
]
const severityClass = severityColorClasses[item.severity]
const isNotification = item.source === 'notification'
const notification = isNotification ? (item.original as Notification) : null
const isUnread = notification?.status === 'new'
const primaryText = getAdvisorPanelItemDisplayTitle(item)
const secondaryText = getAdvisorItemSecondaryText(item, projectNameByRef)
const metadataText =
secondaryText ?? (item.createdAt ? formatItemDate(item.createdAt) : undefined)
// Date strings (e.g. "a few seconds ago") come from formatItemDate and
// need sentence-case capitalisation; entity strings (lint / signal) don't.
const metadataCapitalize = secondaryText === undefined && item.createdAt !== undefined
return (
)
})}
{severityFilters.length > 0 && hiddenItemsCount > 0 && (
)}
>
)
}