Skip to content

feat: allow side elements to opt out of automatic expansion - #3054

Open
minwookshin wants to merge 3 commits into
Chainlit:mainfrom
minwookshin:feat/2932-side-panel-auto-expand
Open

minwookshin wants to merge 3 commits into
Chainlit:mainfrom
minwookshin:feat/2932-side-panel-auto-expand

Conversation

@minwookshin

@minwookshin minwookshin commented Sep 22, 2026

Copy link
Copy Markdown

Addresses #2932.

A new or updated side element currently reopens a panel the user has closed. Add a keyword-only auto_expand=False option to elements, including CustomElement, and carry it as the optional autoExpand live event hint.

The frontend keeps a closed panel closed for opted-out arrivals, updates an already open panel, and still opens it when the user clicks the message reference. Existing callers keep automatic expansion by default. When no side elements remain, cleanup only closes a view still displaying a tracked side element; sidebars opened through ElementSidebar.set_title or set_elements retain their contents, title and key across unrelated inline/page updates.

Before After Why
Every side-element update can reopen the panel Individual arrivals can opt out Lets applications respect a user's reading flow
Explicit reference clicks open side content Explicit clicks still open opted-out elements Preserves direct user control while suppressing automatic opening

Validation: All 938 backend tests on Python 3.13 and all 44 frontend tests pass. The seven new sidebar cases include six preservation regressions that fail before the cleanup fix, including a replacement reusing a tracked ID, and one explicit opt-out element cleanup case. Six API compatibility cases also pass on Python 3.10, covering Text, File and CustomElement with both values of auto_expand. The repository pre-commit checks, including full backend mypy, source/test lint and frontend/react-client typechecks, pass. Repository-wide ESLint/format checks and the embedded copilot build also pass. The production frontend Vite build passes with NODE_OPTIONS=--max-old-space-size=4096; the default 2GB Node heap was insufficient on the validation machine. Existing sourcemap and chunk-size warnings remain. Chrome verification against the real backend covers default opening, quiet Text and CustomElement arrivals, and explicit opening of both kinds. Documentation includes the API and persistence boundary.

The hint is intentionally not persisted; restored historical threads keep their current display behavior. Apply the option to each new or updated element that should remain quiet.


Summary by cubic

Fixes the side panel reopening on every side-element update (issue #2932). Elements can now opt out with auto_expand=False and remain reachable only through their message reference.

  • auto_expand applies to Element and CustomElement and defaults to True.
  • The hint is live-only and not persisted, so restored historical threads keep their current behavior.
  • Explicit reference clicks still open opted-out elements; existing callers are unaffected.
  • Programmatically opened sidebars are preserved when inline/page elements arrive, when tracked content is replaced, or across thread navigation; clearing is limited to views showing tracked side elements.

Written for commit 3077a9a. Summary will update on new commits.

Review in cubic

Co-Authored-By: Codex <noreply@openai.com>

@cubic-dev-ai cubic-dev-ai Bot 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.

All reported issues were addressed across 7 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread frontend/src/components/chat/MessagesContainer/useSideElements.ts
Only clear an empty side-element view when it still displays a side element
tracked by the message hook. Preserve unrelated ElementSidebar state, including
its title and key, when inline or page elements arrive or tracked content is
replaced. Check display as well as ID so a reused ID cannot claim an inline view.

Cover title-only and populated API sidebars, replacements with new or reused
IDs, and cleanup of explicitly opened opt-out elements. Six preservation
regressions fail before this change; all 44 frontend tests pass after it.

Co-Authored-By: Codex <noreply@openai.com>
@minwookshin

Copy link
Copy Markdown
Author

@codex review

@cubic-dev-ai cubic-dev-ai Bot 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.

All reported issues were addressed across 2 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread frontend/src/components/chat/MessagesContainer/useSideElements.ts
Preserve API replacements while cleaning up message-owned panels after remounts and explicit side-element opens.

Co-Authored-By: Codex <noreply@openai.com>

@cubic-dev-ai cubic-dev-ai Bot 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.

1 issue found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="frontend/tests/sideElementsNavigation.spec.tsx">

<violation number="1" location="frontend/tests/sideElementsNavigation.spec.tsx:110">
P3: These `AutoResumeThread` assertions always pass and guard nothing: with `useChatMessages` mocked to `threadId: 'active'`, every render is either the current thread (the `AutoResumeThread` branch in ThreadPage requires `!isCurrentThread`) or a `/share/...` route (it also requires `!isSharedRoute`), so the component can never mount in these tests. Either navigate to a non-current, non-shared route to actually exercise the resume path, or drop the assertion.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

act(() => result.current.navigate('/thread/active'));

expect(screen.getByText('Active thread')).toBeInTheDocument();
expect(AutoResumeThread).not.toHaveBeenCalled();

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.

P3: These AutoResumeThread assertions always pass and guard nothing: with useChatMessages mocked to threadId: 'active', every render is either the current thread (the AutoResumeThread branch in ThreadPage requires !isCurrentThread) or a /share/... route (it also requires !isSharedRoute), so the component can never mount in these tests. Either navigate to a non-current, non-shared route to actually exercise the resume path, or drop the assertion.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/tests/sideElementsNavigation.spec.tsx, line 110:

<comment>These `AutoResumeThread` assertions always pass and guard nothing: with `useChatMessages` mocked to `threadId: 'active'`, every render is either the current thread (the `AutoResumeThread` branch in ThreadPage requires `!isCurrentThread`) or a `/share/...` route (it also requires `!isSharedRoute`), so the component can never mount in these tests. Either navigate to a non-current, non-shared route to actually exercise the resume path, or drop the assertion.</comment>

<file context>
@@ -0,0 +1,144 @@
+    act(() => result.current.navigate('/thread/active'));
+
+    expect(screen.getByText('Active thread')).toBeInTheDocument();
+    expect(AutoResumeThread).not.toHaveBeenCalled();
+    expect(result.current.panel).toBeUndefined();
+  });
</file context>

This branch has not been deployed

No deployments
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.

1 participant