feat:Expand and collaps button added#460
Conversation
✅ Deploy Preview for otel-ecosystem-explorer ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
vitorvasc
left a comment
There was a problem hiding this comment.
Thank you @hussainjamal760!
We could also consider adding controls to collapse or expand a single element when clicking on this section, as well as the visual indicators for that:
What do you think?
Yeah, I understand your point. But I think having what do you think? |
That makes sense. If the visual indicator feels like too much information, we can skip it and use My rationale for allowing elements to be collapsed independently is that some libraries have a lot of metrics, for example: https://deploy-preview-460--otel-ecosystem-explorer.netlify.app/java-agent/instrumentation/2.27.0/grpc-1.6. While collapsing all elements indeed reduces the cognitive load while navigating the page, the usability still isn't quite there yet, since the user currently has to either collapse everything or expand everything. If they want to see the details for a single metric at the bottom of the page, for example, they still have to expand everything and scroll through a bunch of information they don't actually need. |
That’s a fair point, especially for instrumentations with a large number of metrics. I agree that allowing individual sections to be expanded/collapsed would improve navigation and make it easier for users to focus only on the information they need. I still think we should be careful with the visual density of the header row, but using I’ll explore an approach where individual items can be toggled independently without overcrowding the layout. |
There was a problem hiding this comment.
Pull request overview
Adds per-card and "Expand All / Collapse All" controls to the Metrics and Spans lists inside the Java-agent telemetry section. Card bodies are collapsed/expanded individually via a clickable header (chevron + badge), and a pill-shaped segmented control below each section heading toggles every card at once. SectionDivider is extended with an optional className so the new controls can sit flush under it, and three new Vitest cases cover the toggle behavior.
Changes:
- Add
expandedMetrics/expandedSpansstate plus toggle/expand-all/collapse-all handlers inTelemetrySection, including a render-time sync block that resets expansion whencurrentTelemetrychanges. - Restructure metric and span cards into a clickable
role="button"header (with chevron) and a conditionally-rendered detail panel; add duplicated pill-style "Expand All / Collapse All" controls per section. - Allow callers to pass a custom
classNametoSectionDivider, and add tests for click and keyboard toggling.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| ecosystem-explorer/src/features/java-agent/components/telemetry-section.tsx | New expand/collapse state, clickable card headers, and per-section Expand/Collapse All pill controls. |
| ecosystem-explorer/src/features/java-agent/components/telemetry-section.test.tsx | Adds three tests covering click toggle on metric/span headers and Enter/Space keyboard activation. |
| ecosystem-explorer/src/components/ui/section-divider.tsx | Threads an optional className prop through to the wrapper div. |
Comments suppressed due to low confidence (1)
ecosystem-explorer/src/features/java-agent/components/telemetry-section.tsx:269
- Same accessibility issue as the metrics header:
role="button"div with noaria-expanded, noaria-controls, and re-implementing Enter/Space handling that a native<button>would provide. Prefer a real<button type="button">element here.
<div
role="button"
tabIndex={0}
onClick={() => toggleSpan(index.toString())}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
toggleSpan(index.toString());
}
}}
className="flex cursor-pointer items-center justify-between gap-4 p-4 transition-colors hover:bg-white/[0.02] sm:px-6 sm:py-5"
>
| <div | ||
| role="button" | ||
| tabIndex={0} | ||
| onClick={() => toggleMetric(metric.name)} | ||
| onKeyDown={(e) => { | ||
| if (e.key === "Enter" || e.key === " ") { | ||
| e.preventDefault(); | ||
| toggleMetric(metric.name); | ||
| } | ||
| }} | ||
| className="flex cursor-pointer items-center justify-between gap-4 p-4 transition-colors hover:bg-white/[0.02] sm:px-6 sm:py-5" | ||
| > |
| <div className="mt-4 flex justify-center"> | ||
| <div className="border-border/50 bg-muted/80 inline-flex items-center rounded-xl border p-1 shadow-sm backdrop-blur-sm"> | ||
| <button | ||
| type="button" | ||
| onClick={expandAllMetrics} | ||
| className={`flex items-center gap-1.5 rounded-lg px-4 py-2 text-[10px] font-bold tracking-widest uppercase transition-all duration-200 ${ | ||
| expandedMetrics.size === (currentTelemetry.metrics?.length || 0) | ||
| ? "border-secondary/40 bg-secondary/12 text-secondary border shadow-sm" | ||
| : "text-muted-foreground hover:text-foreground border border-transparent" | ||
| }`} | ||
| > | ||
| <Maximize2 className="h-3 w-3" /> | ||
| Expand All | ||
| </button> | ||
| <button | ||
| type="button" | ||
| onClick={collapseAllMetrics} | ||
| className={`flex items-center gap-1.5 rounded-lg px-4 py-2 text-[10px] font-bold tracking-widest uppercase transition-all duration-200 ${ | ||
| expandedMetrics.size === 0 | ||
| ? "border-secondary/40 bg-secondary/12 text-secondary border shadow-sm" | ||
| : "text-muted-foreground hover:text-foreground border border-transparent" | ||
| }`} | ||
| > | ||
| <Minimize2 className="h-3 w-3" /> | ||
| Collapse All | ||
| </button> | ||
| </div> | ||
| </div> |
| const [expandedSpans, setExpandedSpans] = useState<Set<string>>( | ||
| new Set(currentTelemetry?.spans?.map((_, i) => i.toString()) || []) |
| const [expandedMetrics, setExpandedMetrics] = useState<Set<string>>( | ||
| new Set(currentTelemetry?.metrics?.map((m) => m.name) || []) | ||
| ); | ||
| const [expandedSpans, setExpandedSpans] = useState<Set<string>>( | ||
| new Set(currentTelemetry?.spans?.map((_, i) => i.toString()) || []) | ||
| ); | ||
|
|
||
| // Synchronize expanded state when telemetry changes without using useEffect | ||
| const [prevTelemetry, setPrevTelemetry] = useState(currentTelemetry); | ||
| if (currentTelemetry !== prevTelemetry) { | ||
| setPrevTelemetry(currentTelemetry); | ||
| setExpandedMetrics(new Set(currentTelemetry?.metrics?.map((m) => m.name) || [])); | ||
| setExpandedSpans(new Set(currentTelemetry?.spans?.map((_, i) => i.toString()) || [])); | ||
| } | ||
|
|
||
| const expandAllMetrics = () => { | ||
| setExpandedMetrics(new Set(currentTelemetry?.metrics?.map((m) => m.name) || [])); |
| const metricHeader = screen.getByText("http.server.duration").parentElement!; | ||
| await user.click(metricHeader); |
jaydeluca
left a comment
There was a problem hiding this comment.
the feature itself looks good, can you address the copilot comments that I gave a " 👍 " to? then this should be good to go
Sure , |

issue #394
Description: Added Expand All/Collapse All functionality to Telemetry Section
This PR introduces "Expand All" and "Collapse All" controls for the Metrics and Spans sections in the Java Agent instrumentation details page. The goal is to improve information hierarchy and reduce cognitive load by allowing users to toggle the visibility of technical details globally.
Key Changes
Features
UI/UX Enhancements
SegmentedTabListaesthetic:bg-mutedcontainer andsecondaryactive states).histogram,CLIENT Span) to the right side for better readability.Technical Improvements
useEffectstate synchronization with inline state adjustment during render to prevent cascading renders.SectionDividerto support customclassNameprops.Verification Results
telemetry-section.test.tsxpassed successfully.