Skip to content

feat: Add Expand all / Collapse all controls to Configuration Builder#508

Merged
jaydeluca merged 12 commits into
open-telemetry:mainfrom
MeloveGupta:feat/expand-collapse-all-config-builder
Jun 17, 2026
Merged

feat: Add Expand all / Collapse all controls to Configuration Builder#508
jaydeluca merged 12 commits into
open-telemetry:mainfrom
MeloveGupta:feat/expand-collapse-all-config-builder

Conversation

@MeloveGupta

Copy link
Copy Markdown
Contributor

What

Added "Expand all" and "Collapse all" buttons to both the SDK and Instrumentation tabs of the Configuration Builder. Previously users had to click each section individually to expand or collapse it.


Changes

src/features/java-agent/configuration/components/section-expansion-context.tsx (new file)

  • New SectionExpansionProvider context that exposes expandAll() and collapseAll() actions and broadcasts a signal with a nonce so subscriber components re-render on every call, even repeated ones of the same action

src/features/java-agent/configuration/components/group-renderer.tsx

  • Top-level group sections now subscribe to the expansion signal via useSectionExpansion()
  • On expand: sections that are enabled open; disabled sections are left collapsed
  • On collapse: all sections collapse regardless of enabled state

src/features/java-agent/configuration/components/general-section-card.tsx

  • Lifted expansion state from defaultExpanded prop to controlled useState
  • Subscribes to the expansion signal to respond to Expand all / Collapse all

src/features/java-agent/configuration/configuration-builder-page.tsx

  • Wrapped both SdkTabContent and InstrumentationTabBody with SectionExpansionProvider
  • Added ExpandCollapseToolbar component rendering "Expand all | Collapse all" above the section list in both tabs

Before / After

Before After
SDK tab Each section must be expanded individually "Expand all" opens all enabled sections at once; "Collapse all" collapses all
Instrumentation tab Same manual per-section interaction Same Expand all / Collapse all controls

Expand all
Screenshot from 2026-05-18 17-21-53

Collapse all
Screenshot from 2026-05-18 17-22-03


Verified By

  • Clicked "Expand all" on SDK tab - all enabled sections expanded
  • Clicked "Collapse all" on SDK tab - all sections collapsed to headers
  • Clicked "Expand all" on Instrumentation tab - General settings and all instrumentation cards expanded
  • Clicked "Collapse all" on Instrumentation tab - all sections collapsed
  • npx tsc --noEmit - no TypeScript errors

Type of Change

  • Feature

Closes #476

@MeloveGupta MeloveGupta requested review from a team as code owners May 18, 2026 11:54
@netlify

netlify Bot commented May 18, 2026

Copy link
Copy Markdown

Deploy Preview for otel-ecosystem-explorer ready!

Name Link
🔨 Latest commit a818970
🔍 Latest deploy log https://app.netlify.com/projects/otel-ecosystem-explorer/deploys/6a31bdeebed346000887c020
😎 Deploy Preview https://deploy-preview-508--otel-ecosystem-explorer.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@MeloveGupta

Copy link
Copy Markdown
Contributor Author

Hey @lucacavenaghi97 , just pushed a PR!

The initial implementation used useEffect to sync expansion state from the signal, which triggered the react-hooks/set-state-in-effect lint error in CI. I've reworked it to derive the expanded state during render using useMemo instead, the signal's action are used to compute resolvedExpanded directly, which gets passed as the controlled open prop to FieldSection. This avoids the cascading render concern entirely.

Both "Expand all" and "Collapse all" still work correctly on the SDK and Instrumentation tabs, Let me know if you'd like any changes!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds bulk “Expand all” / “Collapse all” controls to the Java Agent Configuration Builder UI (SDK + Instrumentation tabs) by introducing a shared expansion context and wiring section cards to respond to it.

Changes:

  • Added a SectionExpansionProvider + useSectionExpansion() context to broadcast bulk expand/collapse signals.
  • Added an ExpandCollapseToolbar to both tab bodies and wrapped each tab body with the provider.
  • Updated top-level group sections and the general settings section to subscribe to the expansion signal.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
ecosystem-explorer/src/features/java-agent/configuration/configuration-builder-page.tsx Adds toolbar + provider wrappers for SDK/Instrumentation tab bodies.
ecosystem-explorer/src/features/java-agent/configuration/components/section-expansion-context.tsx Introduces context + signal mechanism for bulk expand/collapse.
ecosystem-explorer/src/features/java-agent/configuration/components/group-renderer.tsx Makes top-level group sections respond to bulk expand/collapse.
ecosystem-explorer/src/features/java-agent/configuration/components/general-section-card.tsx Makes the general section card respond to bulk expand/collapse via controlled open state.
Comments suppressed due to low confidence (1)

ecosystem-explorer/src/features/java-agent/configuration/configuration-builder-page.tsx:303

  • In the Instrumentation tab, the toolbar actions only publish a SectionExpansionContext signal, but the instrumentation module rows manage expansion via expandedSet inside InstrumentationBrowser and do not subscribe to this signal. As a result, "Expand all"/"Collapse all" here will only affect GeneralSectionCard, not the instrumentation module details. Either wire the toolbar into InstrumentationBrowser expansion state (e.g., expand all filtered modules / clear set) or adjust scope/UX so the buttons only appear where they actually control visible collapsibles.
        <div className="space-y-4">
          <div className="flex justify-end">
            <ExpandCollapseToolbar />
          </div>
          <div ref={sectionsContainerRef} className="space-y-4">
            <GeneralSectionCard
              label={GENERAL_SETTINGS_LABEL}
              sectionKey={GENERAL_SECTION_KEY}
              children={generalNode?.children ?? []}
              pathPrefix={`${INSTRUMENTATION_DEV_KEY}.${GENERAL_SUBKEY}`}
              defaultExpanded={true}
              emptyMessage="The schema for this version does not expose general instrumentation settings."
            />
            <InstrumentationBrowser
              instrumentations={instrumentationsState.data}
              loading={instrumentationsState.loading}
              error={instrumentationsState.error}
              search={search}
              statusFilter={statusFilter}
              onJumpToGeneral={scrollToSection}
            />

Comment on lines +59 to +67
const { signal } = useSectionExpansion();
const signalExpanded = useMemo(() => {
if (!signal || !isTopLevel) return null;
if (signal.action === "expand") return enabled ? true : null;
if (signal.action === "collapse") return false;
return null;
}, [signal, isTopLevel, enabled]);
const resolvedExpanded = signalExpanded !== null ? signalExpanded : expanded;

Comment on lines +43 to +51
const [expanded, setExpanded] = useState(defaultExpanded);
const { signal } = useSectionExpansion();
const signalExpanded = useMemo(() => {
if (!signal) return null;
if (signal.action === "expand") return true;
if (signal.action === "collapse") return false;
return null;
}, [signal]);
const resolvedExpanded = signalExpanded !== null ? signalExpanded : expanded;
Comment on lines +77 to +99
function ExpandCollapseToolbar() {
const { expandAll, collapseAll } = useSectionExpansion();
return (
<div className="flex items-center gap-2">
<button
type="button"
onClick={expandAll}
className="text-muted-foreground hover:text-foreground text-xs font-medium underline-offset-2 hover:underline"
>
Expand all
</button>
<span className="text-border" aria-hidden="true">
|
</span>
<button
type="button"
onClick={collapseAll}
className="text-muted-foreground hover:text-foreground text-xs font-medium underline-offset-2 hover:underline"
>
Collapse all
</button>
</div>
);
@MeloveGupta

Copy link
Copy Markdown
Contributor Author

Hey @lucacavenaghi97 , I have pushed another update addressing the Copilot feedback!

The previous useMemo approach had a real bug, after clicking "Expand all" or "Collapse all", resolvedExpanded would permanently override the local expanded state, so individual section toggles would stop working. I've fixed this by storing the last seen signal tick in state (lastNonce). During render, if the signal has a new tick, we sync the local expanded state to match the bulk action and record the tick, subsequent renders see the same tick and leave expanded alone, so individual toggles work normally again.

Regarding the integration test suggestion, happy to add that as a follow-up, or I can include it in this PR if you'd prefer it here. Just let me know!

Also, I'd love to have your review on this...

@lucacavenaghi97 lucacavenaghi97 requested a review from Copilot May 19, 2026 17:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

Comment on lines +59 to +65
const { signal } = useSectionExpansion();
const [lastNonce, setLastNonce] = useState<number | null>(null);
if (signal && isTopLevel && signal.nonce !== lastNonce) {
setLastNonce(signal.nonce);
if (signal.action === "expand" && enabled) setExpanded(true);
if (signal.action === "collapse") setExpanded(false);
}
Comment on lines +43 to +50
const [expanded, setExpanded] = useState(defaultExpanded);
const { signal } = useSectionExpansion();
const [lastNonce, setLastNonce] = useState<number | null>(null);
if (signal && signal.nonce !== lastNonce) {
setLastNonce(signal.nonce);
if (signal.action === "expand") setExpanded(true);
if (signal.action === "collapse") setExpanded(false);
}
Comment on lines +53 to +57
return {
expandAll: () => {},
collapseAll: () => {},
signal: null,
};
@MeloveGupta

Copy link
Copy Markdown
Contributor Author

Hey @lucacavenaghi97 , I have pushed another update!

The previous approach of deriving resolvedExpanded from the signal during render had two problems that Copilot correctly flagged, calling setState during render is a React anti-pattern that can cause issues in Strict Mode, and it also permanently overrode local expansion state so individual section toggles stopped working after a bulk action.

I've rearchitected the context to own an overrides map. When "Expand all" or "Collapse all" is clicked, the map is cleared and bulkAction is set. Each section derives its open state from the override map first, then falls back to bulkAction, then to its own local state. When a section is individually toggled, it writes its new state into the override map, so the bulk action stays in effect for all other sections while that one section is independently controlled.

I'd love you you had look on it...

@lucacavenaghi97

Copy link
Copy Markdown
Member

Honestly testing this locally I don't find it very useful in the current shape. On the SDK tab "Expand all" still leaves all the sub-sections (Schedule Delay, Export Timeout, Sampler...) closed, so you still end up clicking through them one by one. On the Instrumentation tab it only opens the General settings card and leaves the 179 module rows untouched, which is probably where users would expect the biggest payoff.

I think we should iterate on this and treat the two tabs separately, since the right behavior is pretty different:

  • SDK tab: expanding only the top-level cards is half the job. Either we open recursively down to the leaf fields, or we keep the bulk control scoped per-card so you can fully open one section at a time without flooding the page.
  • Instrumentation tab: the toolbar should drive the module list as well, otherwise the buttons feel broken on the tab where they would matter most.

@jaydeluca what do you think?

@MeloveGupta the original issue was too narrow on my side, let's wait for Jay's input and then realign.

@MeloveGupta

Copy link
Copy Markdown
Contributor Author

Thanks for the feedback @lucacavenaghi97 !
That makes sense, I can see how the current behavior feels incomplete, especially on the Instrumentation tab where the 179 module rows are untouched.

Happy to wait for @jaydeluca for the input before iterating. Once we align on the right direction for each tab I'll pick it back up...

@jaydeluca

Copy link
Copy Markdown
Member

i agree with @lucacavenaghi97's idea of recursively opening the leafs, and that for the instrumentation tab we should be opening all the instrumentation modules as well

@MeloveGupta

Copy link
Copy Markdown
Contributor Author

Hey @lucacavenaghi97 and @jaydeluca , I just pushed an update addressing both your feedback!

Here's what I changed:

SDK tab - "Expand all" now recursively opens all nested sections down to the leaf fields (Schedule Delay, Export Timeout, Sampler, Readers, Detectors, etc.), not just the top-level cards. "Collapse all" collapses everything recursively too. Individual section toggles still work independently after a bulk action.

Instrumentation tab - "Expand all" now also drives the 178 module rows in the instrumentation list, opening each row to show its configurable options. "Collapse all" closes them all. Individual row toggles still work independently.

Also resolved a few merge conflicts with upstream changes (activePreviewKey, handleInteraction, PruneInstrumentationsForAgentVersion) along the way.

Let me know if this is closer to what you had in mind, or if you'd like any further adjustments!

@lucacavenaghi97

Copy link
Copy Markdown
Member

Tested on the deploy preview (SDK tab): "Expand all" still doesn't open the leaf fields. It only expands the top couple of levels, the actual leaves (Schedule Delay, Export Timeout, Exporter, Limits, etc.) stay collapsed. "Collapse all" works fine.

@MeloveGupta

Copy link
Copy Markdown
Contributor Author

@lucacavenaghi97 , I'll have a look into it, and update the PR shortly...

@lucacavenaghi97

Copy link
Copy Markdown
Member

Hi @MeloveGupta ! I noticed this PR has been inactive for about a week. Do you plan to continue working on it in the next few days, or would you prefer that I take over and finish it? I'd be happy to help move it forward and get it merged. Let me know what works best for you. Thanks!

@MeloveGupta

Copy link
Copy Markdown
Contributor Author

Hey @lucacavenaghi97 , Sorry for the delay, actually for the last few days I have been caught up with my End Sems and some travelling, I do wish to continue on this issue but I am still travelling so I would atleast require a week or so to continue the work and update the PR. But, if the issue is important and is getting held back then I'd be more than happy for you to take it up...

@lucacavenaghi97

Copy link
Copy Markdown
Member

No problem at all! Thanks. There's no rush on this one, so take your time and continue whenever you're back and have some bandwidth. Good luck with your exams, and enjoy your travels! 🙂

@MeloveGupta MeloveGupta force-pushed the feat/expand-collapse-all-config-builder branch from bdedfed to 80d0c5f Compare June 12, 2026 07:28
@MeloveGupta MeloveGupta force-pushed the feat/expand-collapse-all-config-builder branch from c673538 to a2dd654 Compare June 14, 2026 18:00
@MeloveGupta

MeloveGupta commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Tested on the deploy preview (SDK tab): "Expand all" still doesn't open the leaf fields. It only expands the top couple of levels, the actual leaves (Schedule Delay, Export Timeout, Exporter, Limits, etc.) stay collapsed. "Collapse all" works fine.

Hi @lucacavenaghi97 , what I found out was that the root cause was in two places:

  1. schema-renderer.tsx - the wrap() function for leaf fields (text inputs, toggles, number inputs, etc.) was using defaultExpanded only and never reading bulkAction from SectionExpansionContext. Added a WrappedLeaf component that mirrors the same bulk action logic used by GroupRenderer.

  2. group-renderer.tsx - non-top-level groups were using open={expanded} instead of open={resolvedExpanded}, so nested groups like Limits were also ignoring the bulk action.

Also made useSectionExpansion return a safe no-op fallback when used outside a provider, which fixed two unit tests that rendered SchemaRenderer in isolation without a SectionExpansionProvider wrapper.

Both Expand all and Collapse all are now fully working across all levels - groups, nested groups, and leaf fields. Tested locally across all SDK sections.

Could you review all the changes and tell me if any further changes are required from my side.

Resolve conflicts in instrumentation-browser, schema-renderer and
configuration-builder-page: keep the SectionExpansionProvider/toolbar
wiring while adopting the i18n labels introduced on main.
Wire the union, list and plugin-select renderers into the section
expansion context so Expand all and Collapse all drive every collapsible
at any depth, on both the SDK and Instrumentation tabs.

Extract the open-state resolution into a shared resolveBulkOpen helper and
a useCollapsibleExpansion hook, keyed by path so repeated node keys
(processors, exporter, attributes) no longer collide when toggling a
single section. Add an integration test covering both tabs and restyle the
toolbar buttons to match the existing toolbar.
@lucacavenaghi97

Copy link
Copy Markdown
Member

Thanks a lot @MeloveGupta for the work here! I pushed a small update on top: merged main to clear the conflicts and made Expand/Collapse all reach every nested section on both tabs, plus an integration test. Hope that's ok with you!

@jaydeluca jaydeluca added this pull request to the merge queue Jun 17, 2026
Merged via the queue into open-telemetry:main with commit 63bd564 Jun 17, 2026
23 checks passed
@otelbot

otelbot Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Thank you for your contribution @MeloveGupta! 🎉 We would like to hear from you about your experience contributing to OpenTelemetry by taking a few minutes to fill out this survey.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Expand all / Collapse all controls to the Configuration Builder

4 participants