feat(advisory): implement CSAF Product Tree tab with ECharts tree visualization#1066
feat(advisory): implement CSAF Product Tree tab with ECharts tree visualization#1066CryptoRodeo wants to merge 3 commits into
Conversation
Define TypeScript interfaces for the full CSAF 2.0 VEX document structure (CsafDocument, CsafVulnerability, CsafProductTree, etc.) and add useFetchAdvisoryCsafById query hook that fetches raw CSAF JSON via the downloadAdvisory endpoint and parses the Blob into typed data. Also add echarts and echarts-for-react dependencies for upcoming tree visualization components. Implements TC-4618 Assisted-by: Claude Code
When advisory labels.type === "csaf", render a CSAF-specific 5-tab layout (Overview, Vulnerabilities, Product Tree, Relationship Tree, Source) instead of the default 2-tab Info/Vulnerabilities view. The CsafAdvisoryDetails component fetches the parsed CSAF document via useFetchAdvisoryCsafById and provides placeholder content for each tab that subsequent tasks will replace with real implementations. Implements TC-4619 Assisted-by: Claude Code
…ualization Add interactive ECharts tree rendering of CSAF product_tree.branches hierarchy (vendor → product family → product name → product version). Features: - Left-to-right tree layout with expand/collapse, zoom, and pan - Color-coded nodes by branch category with legend - Auto-collapse subtrees with >40 leaves - Empty state when no product tree data exists - React.useMemo for data transformation performance Implements TC-4622 Assisted-by: Claude Code
Reviewer's GuideImplements a CSAF-specific advisory details view with a new Product Tree tab that renders CSAF product_tree.branches as an interactive ECharts tree, adds CSAF typings and query hook to fetch the raw CSAF JSON, and conditionally switches advisory details layout for CSAF advisories while introducing reusable helpers for tree transformation and styling. Sequence diagram for CSAF advisory product tree renderingsequenceDiagram
actor User
participant AdvisoryDetails
participant CsafAdvisoryDetails
participant useFetchAdvisoryCsafById
participant downloadAdvisory
participant CsafProductTree
participant transformBranchesToTreeData
participant ReactECharts
User->>AdvisoryDetails: open advisory (csaf type)
AdvisoryDetails->>CsafAdvisoryDetails: render with advisoryId
CsafAdvisoryDetails->>useFetchAdvisoryCsafById: advisoryId
useFetchAdvisoryCsafById->>downloadAdvisory: { client, path.key }
downloadAdvisory-->>useFetchAdvisoryCsafById: Blob
useFetchAdvisoryCsafById-->>CsafAdvisoryDetails: csafDocument
CsafAdvisoryDetails->>CsafProductTree: csafDocument
CsafProductTree->>transformBranchesToTreeData: product_tree.branches
transformBranchesToTreeData-->>CsafProductTree: EChartsTreeNode root
CsafProductTree->>ReactECharts: option.series[0].data = [root]
ReactECharts-->>User: interactive tree visualization
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- In
CsafAdvisoryDetails, the tab refs are created withReact.createRef()inside the component body, which recreates them on every render; switch these touseRefso the refs remain stable across renders and avoid potential focus/TabContent issues. - The
countLeaveshelper incsaf-tree-helpers.tsis called once per branch intransformBranch, making the overall transform O(n²) on large trees; consider refactoring to compute leaf counts in a single post-order traversal and reuse the results when buildingEChartsTreeNodes.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `CsafAdvisoryDetails`, the tab refs are created with `React.createRef()` inside the component body, which recreates them on every render; switch these to `useRef` so the refs remain stable across renders and avoid potential focus/TabContent issues.
- The `countLeaves` helper in `csaf-tree-helpers.ts` is called once per branch in `transformBranch`, making the overall transform O(n²) on large trees; consider refactoring to compute leaf counts in a single post-order traversal and reuse the results when building `EChartsTreeNode`s.
## Individual Comments
### Comment 1
<location path="client/src/app/pages/advisory-details/advisory-details.tsx" line_range="92" />
<code_context>
useDeleteAdvisoryMutation(onDeleteAdvisorySuccess, onDeleteAdvisoryError);
- // Tabs
+ const isCsaf = advisory?.labels.type === "csaf";
+
+ // Tabs (default non-CSAF layout)
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard against missing `labels` when checking CSAF type.
If `labels` can be undefined, `advisory?.labels.type` will still throw. Use `advisory?.labels?.type === "csaf"` (or a safe accessor) to avoid a runtime error when `labels` is missing.
</issue_to_address>
### Comment 2
<location path="client/src/app/pages/advisory-details/csaf-advisory-details.tsx" line_range="58-62" />
<code_context>
+ ],
+ });
+
+ const overviewTabRef = React.createRef<HTMLElement>();
+ const vulnerabilitiesTabRef = React.createRef<HTMLElement>();
+ const productTreeTabRef = React.createRef<HTMLElement>();
+ const relationshipTreeTabRef = React.createRef<HTMLElement>();
+ const sourceTabRef = React.createRef<HTMLElement>();
+
+ return (
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Use `useRef` instead of `createRef` for tab content refs inside a function component.
Using `React.createRef` in a function component recreates these refs on every render, which can break the linkage between each `Tab`’s `tabContentRef` and its `TabContent`. Using `React.useRef<HTMLElement>(null)` instead keeps each ref stable across renders, matching how the PatternFly tabs expect refs to work.
```suggestion
const overviewTabRef = React.useRef<HTMLElement | null>(null);
const vulnerabilitiesTabRef = React.useRef<HTMLElement | null>(null);
const productTreeTabRef = React.useRef<HTMLElement | null>(null);
const relationshipTreeTabRef = React.useRef<HTMLElement | null>(null);
const sourceTabRef = React.useRef<HTMLElement | null>(null);
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| const overviewTabRef = React.createRef<HTMLElement>(); | ||
| const vulnerabilitiesTabRef = React.createRef<HTMLElement>(); | ||
| const productTreeTabRef = React.createRef<HTMLElement>(); | ||
| const relationshipTreeTabRef = React.createRef<HTMLElement>(); | ||
| const sourceTabRef = React.createRef<HTMLElement>(); |
There was a problem hiding this comment.
suggestion (bug_risk): Use useRef instead of createRef for tab content refs inside a function component.
Using React.createRef in a function component recreates these refs on every render, which can break the linkage between each Tab’s tabContentRef and its TabContent. Using React.useRef<HTMLElement>(null) instead keeps each ref stable across renders, matching how the PatternFly tabs expect refs to work.
| const overviewTabRef = React.createRef<HTMLElement>(); | |
| const vulnerabilitiesTabRef = React.createRef<HTMLElement>(); | |
| const productTreeTabRef = React.createRef<HTMLElement>(); | |
| const relationshipTreeTabRef = React.createRef<HTMLElement>(); | |
| const sourceTabRef = React.createRef<HTMLElement>(); | |
| const overviewTabRef = React.useRef<HTMLElement | null>(null); | |
| const vulnerabilitiesTabRef = React.useRef<HTMLElement | null>(null); | |
| const productTreeTabRef = React.useRef<HTMLElement | null>(null); | |
| const relationshipTreeTabRef = React.useRef<HTMLElement | null>(null); | |
| const sourceTabRef = React.useRef<HTMLElement | null>(null); |
There was a problem hiding this comment.
[sdlc-workflow/verify-pr] Classified as suggestion — createRef vs useRef is a pre-existing codebase convention. No sub-task created.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1066 +/- ##
==========================================
- Coverage 49.17% 48.64% -0.54%
==========================================
Files 253 256 +3
Lines 5499 5557 +58
Branches 1660 1670 +10
==========================================
- Hits 2704 2703 -1
- Misses 2519 2579 +60
+ Partials 276 275 -1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Verification Report for TC-4622 (commit 22cdbfc)
Overall: PASSThis comment was AI-generated by sdlc-workflow/verify-pr v0.9.1. |
Summary
product_tree.brancheshierarchy (vendor → product family → product name → product version)React.useMemofor data transformation performancecsaf-tree-helpers.tsfor reuse by Relationship Tree tabTest plan
npm run build -w client)Implements TC-4622
Assisted-by: Claude Code
Summary by Sourcery
Add CSAF-specific advisory details view with a product tree visualization and supporting CSAF data types and query.
New Features:
Enhancements:
Build: