Skip to content

feat: implement open/closing logic for modernized content uploader#4628

Merged
mergify[bot] merged 3 commits into
box:masterfrom
olehrybak:modernized-uploader-open-close
Jun 17, 2026
Merged

feat: implement open/closing logic for modernized content uploader#4628
mergify[bot] merged 3 commits into
box:masterfrom
olehrybak:modernized-uploader-open-close

Conversation

@olehrybak

@olehrybak olehrybak commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Implemented the logic to open the modernized content uploader when files are added to the queue
  • Added the new conditions to close the uploader after timer elapses and resetting it based on multiple conditions (hovering and focusing the uploader, adding new items to the queue)
  • Added modernized animations for both opening and closing

Summary by CodeRabbit

  • New Features
    • Added a modernized uploads manager panel that auto-dismisses when the current batch is fully complete or canceled.
    • Panel dismissal is paused during mouse hover and keyboard focus, then resumes afterward.
    • Slide-in/slide-out behavior updated, including reduced-motion support.
  • Bug Fixes
    • Improved modernized flow terminal handling (canceled as terminal) and queue reset behavior to better match expected panel lifecycle.
  • Tests
    • Added Jest coverage for panel open/close, dismiss-timer behavior, interaction edge cases, animation-end finalization, rapid batch handling, and unmount cleanup.
  • Documentation
    • Updated the ContentUploader story to enable modernized uploads with mocked API endpoints and sample files.

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds a modernized uploads manager panel with slide-in/slide-out CSS animations to ContentUploader. The panel auto-dismisses after a timed delay when a batch completes, with the timer paused by hover and keyboard focus. Legacy queue-clearing is suppressed when enableModernizedUploads is enabled, and queue reset is deferred until the slide-out animation finishes.

Changes

Modernized Uploads Manager Panel Dismiss Lifecycle

Layer / File(s) Summary
State types, constants, and initial setup
src/elements/content-uploader/ContentUploader.tsx
Defines ModernizedPanelState type (hidden, shown, dismissing), SLIDE_OUT_ANIMATION_NAME constant, instance fields for timer and interaction guards, and initializes modernizedPanelState to hidden; imports panel stylesheet.
Panel animations and CSS styling
src/elements/content-uploader/ModernizedUploadsManagerPanel.scss
Defines keyframe animations bcu-modernized-slideIn and bcu-modernized-slideOut, and state-driven CSS rules for visible/dismissing/hidden panel states with a prefers-reduced-motion media query override.
Lifecycle methods and interaction handlers
src/elements/content-uploader/ContentUploader.tsx
Adds methods to control the dismiss timer (clear, start, finalize), show the panel, and event handlers for mouse enter/leave and keyboard focus/blur that pause/resume the dismissal countdown; slide-out animation end handler to finalize dismissal and clear timer on unmount.
componentDidUpdate orchestration and state-driven timer logic
src/elements/content-uploader/ContentUploader.tsx
Updates componentDidUpdate to show the modernized panel when items exist, start the dismiss timer when all items are complete/canceled, and clear the timer when uploads become in-progress or error mid-wait.
Legacy behavior suppression and queue reset guards
src/elements/content-uploader/ContentUploader.tsx
Adds early-return in checkClearUploadItems when enableModernizedUploads is enabled to prevent legacy timeout-driven queue clearing; adjusts resetUploadsManagerItemsWhenUploadsComplete so the expanded/in-progress guard does not apply in modernized flow.
Modernized panel lifecycle test suite
src/elements/content-uploader/__tests__/ContentUploader.test.js
Comprehensive Jest fake-timer suite covering timer initialization and delay, state transitions, cancellation on item changes, hover and focus interaction guards, animation-gated finalization, multi-batch ordering, unmount cleanup, state initialization, and feature-flag-off behavior.
Storybook story MSW mocks and example args
src/elements/content-uploader/stories/ContentUploader.stories.js
Extends withModernizedUploads story with useUploadsManager: true, three sample File objects, and MSW handlers mocking the upload options and post endpoints using DEFAULT_HOSTNAME_API and DEFAULT_HOSTNAME_UPLOAD constants.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ContentUploader
  participant modernizedPanelState
  participant DismissTimer

  User->>ContentUploader: Uploads batch starts
  ContentUploader->>modernizedPanelState: showModernizedPanel() → 'shown'
  ContentUploader->>ContentUploader: componentDidUpdate detects batch complete
  ContentUploader->>DismissTimer: startModernizedDismissTimer()
  User->>ContentUploader: Mouse hover enter
  ContentUploader->>DismissTimer: clearModernizedDismissTimer()
  User->>ContentUploader: Mouse hover leave
  ContentUploader->>DismissTimer: startModernizedDismissTimer()
  DismissTimer->>modernizedPanelState: delay expires → 'dismissing'
  Note over modernizedPanelState: slideOut animation plays
  ContentUploader->>modernizedPanelState: animationend (slideOut) → finalizeModernizedDismiss() → 'hidden'
  ContentUploader->>ContentUploader: Reset uploads queue
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • box/box-ui-elements#4629: Modifies the same resetUploadsManagerItemsWhenUploadsComplete queue-reset guard path to accommodate controlled/uncontrolled expanded state.
  • box/box-ui-elements#4579: Wired CancelAllUploadsModal into ContentUploader, which this PR wraps inside the modernized panel div alongside UploadsManagerBP.
  • box/box-ui-elements#4578: Both PRs treat STATUS_CANCELED as a terminal completion state and suppress the onComplete callback when no items finish successfully.

Suggested reviewers

  • jpan-box
  • reneshen0328

🐇 A panel slides in, smooth and bright,
Uploads queued up, then done just right.
A timer ticks — hover to pause,
The rabbit checks each blurring clause.
Slide out, fade gone, the queue resets,
No legacy ghosts, no lingering debts! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: implementing open/closing logic for the modernized content uploader, which aligns with the actual changes across the ContentUploader component, new SCSS animations, and test coverage.
Description check ✅ Passed The description provides a clear summary of the three main changes (opening logic, closing conditions with timer resets, and animations) and aligns well with the PR objectives and actual implementation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@olehrybak olehrybak marked this pull request as ready for review June 15, 2026 15:43
@olehrybak olehrybak requested review from a team as code owners June 15, 2026 15:43

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/elements/content-uploader/ContentUploader.tsx`:
- Around line 286-287: The componentDidUpdate method is calling
startModernizedDismissTimer() on every update while modernizedPanelState remains
'shown', which continuously restarts the dismiss timeout. Instead, only call
startModernizedDismissTimer() when modernizedPanelState transitions TO 'shown'
from a different state. Track the previous modernizedPanelState value in
componentDidUpdate and compare it with the current modernizedPanelState to
detect the actual state transition, ensuring the timer is only reset when
entering the 'shown' state rather than on every update.

In `@src/elements/content-uploader/ModernizedUploadsManagerPanel.scss`:
- Around line 1-44: Rename the keyframe animations in the SCSS file to use fully
kebab-case naming: change bcu-modernized-slideIn to bcu-modernized-slide-in and
bcu-modernized-slideOut to bcu-modernized-slide-out in all animation references
within the .bcu-modernized-panel class. Then update the SLIDE_OUT_ANIMATION_NAME
constant and its usage in the handleModernizedAnimationEnd function in the
corresponding TypeScript file to reference the renamed bcu-modernized-slide-out
keyframe to ensure the animation end event handling continues to work correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8d5492a4-d2b1-4b6c-a9a0-dfd5c4482668

📥 Commits

Reviewing files that changed from the base of the PR and between 7f63ba1 and 9b4ad3a.

📒 Files selected for processing (4)
  • src/elements/content-uploader/ContentUploader.tsx
  • src/elements/content-uploader/ModernizedUploadsManagerPanel.scss
  • src/elements/content-uploader/__tests__/ContentUploader.test.js
  • src/elements/content-uploader/stories/ContentUploader.stories.js

Comment thread src/elements/content-uploader/ContentUploader.tsx Outdated
Comment thread src/elements/content-uploader/ModernizedUploadsManagerPanel.scss
dealwith
dealwith previously approved these changes Jun 16, 2026

@dealwith dealwith 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.

Looks good, didn't find blocking issues 👍

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/elements/content-uploader/__tests__/ContentUploader.test.js (1)

1445-1699: ⚡ Quick win

Add test coverage for STATUS_CANCELED items in the dismiss timer lifecycle.

The implementation treats STATUS_CANCELED items as complete when determining whether to start the dismiss timer (as shown in the upstream isUploadsBatchSuccessfullyComplete check). The test suite verifies STATUS_COMPLETE, STATUS_IN_PROGRESS, and STATUS_ERROR but doesn't explicitly test that a batch with only STATUS_CANCELED items triggers the dismiss timer.

Consider adding a test case to verify this behavior.

🧪 Suggested test case
test('starts dismiss timer when all items are STATUS_CANCELED', () => {
    const wrapper = getWrapper({ enableModernizedUploads: true });
    const instance = wrapper.instance();
    
    wrapper.setState({
        modernizedPanelState: 'shown',
        items: [makeItem('a.pdf', STATUS_CANCELED), makeItem('b.pdf', STATUS_CANCELED)],
    });

    expect(instance.modernizedDismissTimer).not.toBeNull();
    
    jest.advanceTimersByTime(HIDE_DELAY_MS);
    expect(wrapper.state('modernizedPanelState')).toBe('dismissing');
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/elements/content-uploader/__tests__/ContentUploader.test.js` around lines
1445 - 1699, Add a new test case within the 'modernized panel open/close
lifecycle' describe block to verify that the dismiss timer is started when all
items transition to STATUS_CANCELED status. The test should create a batch with
only STATUS_CANCELED items (following the pattern of the existing test cases
like 'starts dismiss timer when batch transitions to all-complete and panel is
shown'), verify that the modernizedDismissTimer is set, advance the timer by
HIDE_DELAY_MS, and then assert that the modernizedPanelState transitions to
'dismissing'. This ensures STATUS_CANCELED items are properly treated as
complete items for the dismiss timer logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/elements/content-uploader/__tests__/ContentUploader.test.js`:
- Line 1614: The test file is using a hardcoded string 'bcu-modernized-slideOut'
in the handleModernizedAnimationEnd call instead of referencing the
implementation's constant. Import the SLIDE_OUT_ANIMATION_NAME constant from the
implementation module and replace the hardcoded string with this constant in the
test assertion to ensure the test remains synchronized if the constant value
changes in the future.
- Line 1446: The test file defines a local constant HIDE_DELAY_MS = 8000 instead
of importing the actual constant from the implementation. This creates a drift
risk where the test could pass even if the implementation constant
HIDE_UPLOAD_MANAGER_DELAY_MS_DEFAULT changes. Import
HIDE_UPLOAD_MANAGER_DELAY_MS_DEFAULT from the ContentUploader implementation
file at the top of the test file, then replace all uses of the locally defined
HIDE_DELAY_MS with the imported HIDE_UPLOAD_MANAGER_DELAY_MS_DEFAULT constant to
keep the test synchronized with the production code.

---

Nitpick comments:
In `@src/elements/content-uploader/__tests__/ContentUploader.test.js`:
- Around line 1445-1699: Add a new test case within the 'modernized panel
open/close lifecycle' describe block to verify that the dismiss timer is started
when all items transition to STATUS_CANCELED status. The test should create a
batch with only STATUS_CANCELED items (following the pattern of the existing
test cases like 'starts dismiss timer when batch transitions to all-complete and
panel is shown'), verify that the modernizedDismissTimer is set, advance the
timer by HIDE_DELAY_MS, and then assert that the modernizedPanelState
transitions to 'dismissing'. This ensures STATUS_CANCELED items are properly
treated as complete items for the dismiss timer logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a3a27d40-a1c6-4ffa-8be8-8c40477da90a

📥 Commits

Reviewing files that changed from the base of the PR and between 86959e8 and fa35eec.

📒 Files selected for processing (4)
  • src/elements/content-uploader/ContentUploader.tsx
  • src/elements/content-uploader/ModernizedUploadsManagerPanel.scss
  • src/elements/content-uploader/__tests__/ContentUploader.test.js
  • src/elements/content-uploader/stories/ContentUploader.stories.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/elements/content-uploader/stories/ContentUploader.stories.js
  • src/elements/content-uploader/ContentUploader.tsx

Comment thread src/elements/content-uploader/__tests__/ContentUploader.test.js
Comment thread src/elements/content-uploader/__tests__/ContentUploader.test.js

@jfox-box jfox-box 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.

LGTM

@mergify

mergify Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-06-17 22:26 UTC · Rule: Automatic strict merge
  • Checks skipped · PR is already up-to-date
  • Merged2026-06-17 22:26 UTC · at fa35eec22e135264cc4c4586ce0affce33fb2288 · squash

This pull request spent 10 seconds in the queue, including 1 second running CI.

Required conditions to merge

@mergify mergify Bot merged commit f7ecc3a into box:master Jun 17, 2026
10 of 11 checks passed
@mergify mergify Bot removed the queued label Jun 17, 2026
kduncanhsu pushed a commit to kduncanhsu/box-ui-elements that referenced this pull request Jun 18, 2026
…ox#4628)

* feat: implement open/closing logic for modernized content uploader

* test: update storybook

* fix: avoid starting timer on every re-render
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants