"use client"; import Link from "next/link"; import { IssueAttackPath } from "@/components/issues/issue-attack-path"; import { IssueTriage } from "@/components/issues/issue-triage"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/shadcn"; import { Badge } from "@/components/shadcn/badge/badge"; import { Button } from "@/components/shadcn/button/button"; import { EntityInfo } from "@/components/shadcn/entities"; import { InfoField } from "@/components/shadcn/info-field/info-field"; import { SeverityBadge } from "@/components/shadcn/table/severity-badge"; import { DetailSidePanel } from "@/components/side-panel/detail-side-panel"; import { LEG_LABELS, LEG_QUESTIONS, LEG_STATE_LABELS, legBadgeVariant, VERDICTS, } from "@/lib/issues/verdicts"; import { ATTACKER_START_LABEL, ISSUE_OUTCOME_LABEL, IssueResource, LegName, } from "@/types/issues"; interface IssuePanelProps { issue: IssueResource; open: boolean; onOpenChange: (open: boolean) => void; } /** * The verdict and the reasoning behind it, from the list row alone (no * fetch). Graph, resources, findings and compliance stay on the issue page. */ export const IssuePanel = ({ issue, open, onOpenChange }: IssuePanelProps) => { const { attributes } = issue; const verdict = VERDICTS.find((item) => item.id === attributes.verdict); const scanId = issue.relationships?.scan?.data?.id; const providerId = issue.relationships?.provider?.data?.id; return (
{verdict?.label ?? attributes.verdict}

{attributes.title}

{attributes.findings_count.toLocaleString()}{" "} {attributes.findings_count === 1 ? "finding" : "findings"} ยท{" "} {attributes.pattern}

Exploitability Attack path Remediation Triage
{attributes.attacker_start && attributes.outcome && (
{ATTACKER_START_LABEL[attributes.attacker_start]} {ISSUE_OUTCOME_LABEL[attributes.outcome]}
)}
    {(Object.keys(LEG_LABELS) as LegName[]).map((name) => { const leg = attributes.legs[name]; if (!leg) return null; return (
  • {LEG_LABELS[name]} {LEG_QUESTIONS[name]} {leg.text}
    {LEG_STATE_LABELS[leg.state]}
  • ); })}
{/* Mounted only while selected, so the graph's requests run when someone asks for it. */}

{attributes.fix}

{scanId && ( )}
); };