Skip to content

Improve spreadsheet-first workspace and docked chat UX#13

Merged
Ocean82 merged 5 commits into
mainfrom
arena/019f987a-smartshit
Jul 25, 2026
Merged

Improve spreadsheet-first workspace and docked chat UX#13
Ocean82 merged 5 commits into
mainfrom
arena/019f987a-smartshit

Conversation

@Ocean82

@Ocean82 Ocean82 commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Summary by Sourcery

Improve docked panel UX and accessibility in the spreadsheet-first workspace, refine mobile behavior for docked tools and chat, and replace panel type definitions with richer icon- and sizing-aware metadata.

New Features:

  • Add keyboard-accessible resizing for docked panels via the resize separator.
  • Make docked tools become intentional full-screen workspaces on phones instead of compressing the sheet into a narrow column.
  • Define panel metadata in a new React-based panelTypes module including icons and width constraints for each panel.

Enhancements:

  • Adjust dock panel layout and width constraints so tools no longer float over or overly compress the spreadsheet grid on larger screens.
  • Refine spreadsheet main area minimum widths across breakpoints to preserve sheet usability alongside docked tools.
  • Improve the chat panel header copy and replace the mobile close glyph with an accessible icon button.
  • Add ARIA attributes and pointer handling tweaks to the resize separator to provide a predictable, touch-friendly hit area and better assistive technology support.
  • Respect prefers-reduced-motion settings by minimizing scroll, transition, and animation durations globally.

Summary by CodeRabbit

  • New Features
    • Added keyboard controls for panel resizing (step, min, max) alongside improved pointer-based resizing.
    • Mobile dock panels now switch to a full-screen workspace layout.
  • Improvements
    • Refreshed the assistant standalone-mode subtitle text.
    • Updated the mobile close button to use a proper icon and added a clear close label for accessibility.
    • Added reduced-motion support to lessen scrolling and animation effects.

Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 25, 2026 08:58
@sourcery-ai

sourcery-ai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Reviewer's Guide

Refactors docked panel behavior and styling to improve spreadsheet-first workspace UX, adds keyboard-accessible resizing, adjusts mobile layout of docked tools, and updates chat panel copy and icon while introducing typed panel definitions.

Sequence diagram for keyboard-accessible dock panel resizing

sequenceDiagram
  actor User
  participant DockPanel
  participant PanelStore

  User->>DockPanel: handleResizeKeyDown(event)
  alt e.key is ArrowLeft
    DockPanel->>DockPanel: resizeBy(20)
  else e.key is ArrowRight
    DockPanel->>DockPanel: resizeBy(-20)
  else e.key is Home
    DockPanel->>PanelStore: setPanelWidth(panelId, def.minWidth)
  else e.key is End
    DockPanel->>PanelStore: setPanelWidth(panelId, def.maxWidth)
  end
  DockPanel->>PanelStore: setPanelWidth(panelId, clampedWidth)  Note over DockPanel,PanelStore: From resizeBy
Loading

File-Level Changes

Change Details Files
Improve dock panel resizing behavior, accessibility, and responsive layout so tools better coexist with the spreadsheet grid.
  • Refactored resize logic into a reusable resizeBy helper with min/max width clamping.
  • Switched mouse-based resize listeners to pointer events with pointer capture and updated event cleanup.
  • Added keyboard handling on the resize separator to support Arrow/Home/End keys for accessible resizing.
  • Updated dock panel container classes and inline styles to support responsive fixed layout on small screens and constrain max width relative to viewport.
  • Enhanced separator element with ARIA value attributes, tab focus, and hidden on small screens to avoid unusable resize affordance.
src/components/panels/DockPanel.tsx
Adjust global styles to keep docked tools from overlapping the sheet, improve touch affordance, honor reduced motion preferences, and make dock panels full-screen on phones.
  • Set minimum width and background for the spreadsheet main area to prevent docked tools from floating over the grid.
  • Disabled touch-action on vertical separator elements to make the resize hit area predictable on touch devices.
  • Added prefers-reduced-motion rules to effectively disable smooth scrolling and long transitions/animations.
  • Forced dock panels to take full width on narrow viewports with relaxed min/max width constraints.
src/index.css
Polish chat panel UX with more task-oriented helper text and an accessible icon-based close button on mobile.
  • Updated the chat header helper text to emphasize sheet-related queries and modifications.
  • Replaced the text-based mobile close control with a Lucide X icon component marked aria-hidden for accessibility consistency.
src/components/ChatPanel.tsx
Introduce typed panel definitions with icons and width constraints for all dockable tools and migrate from the old untyped configuration.
  • Defined PanelId union type and PanelDef interface capturing id, icon, label, and width bounds for panels.
  • Created a PANELS registry with definitions for chat, insights, auditor, and inspector panels including Lucide icons.
  • Implemented a getPanelDef helper to retrieve panel definitions by id.
  • Removed the previous TypeScript panelTypes file in favor of the new typed TSX configuration.
src/components/panels/panelTypes.tsx
src/components/panels/panelTypes.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Ocean82, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 13 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bf85e4c8-9fd4-4de9-ac71-1a479b331a47

📥 Commits

Reviewing files that changed from the base of the PR and between c41bf4c and e7c3320.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • src/components/ChatPanel.tsx
  • src/components/panels/DockPanel.tsx
  • src/components/panels/panelTypes.tsx
📝 Walkthrough

Walkthrough

The PR adds panel metadata definitions, pointer and keyboard DockPanel resizing, responsive workspace styling, reduced-motion behavior, and updated ChatPanel text and mobile close-button accessibility.

Changes

Workspace panel interactions

Layer / File(s) Summary
Panel definitions
src/components/panels/panelTypes.ts, src/components/panels/panelTypes.tsx
Panel identifiers, metadata, concrete configurations, and lookup behavior are defined in the new .tsx module.
Dock resizing and workspace styling
src/components/panels/DockPanel.tsx, src/index.css
Dock resizing supports pointer and keyboard input with viewport-aware bounds and ARIA state; CSS adds responsive workspace sizing, reduced-motion rules, and full-width mobile panels.

Chat presentation

Layer / File(s) Summary
Chat header and mobile close control
src/components/ChatPanel.tsx
The standalone subheading changes, and the mobile close control uses the Lucide X icon with an accessible label.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant DockPanel
  participant Browser
  User->>DockPanel: pointerdown on resize handle
  DockPanel->>Browser: capture pointer and apply drag styles
  User->>DockPanel: move pointer
  DockPanel->>DockPanel: update bounded panel width
  User->>DockPanel: release pointer
  DockPanel->>Browser: release pointer and reset drag styles
  User->>DockPanel: press resize key
  DockPanel->>DockPanel: apply keyboard width change
Loading

Poem

I nudged the panels wide and bright,
With arrows guiding left and right.
A tiny X now bids farewell,
While quiet styles make motion swell—
Hop, hop, the workspace fits just right!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main UX improvements to the spreadsheet-first workspace and docked chat.
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.

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.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • The resizable separator mixes role="separator" with slider-like aria-valuemin/max/now and keyboard behavior; consider either switching to role="slider" or simplifying the ARIA to match separator semantics so assistive tech interprets it correctly.
  • In the resize implementation you both call setPointerCapture on the handle and attach global pointermove/pointerup listeners on document; you can likely simplify this by relying on pointer capture and handling events on the element itself to avoid the extra global listeners and cleanup complexity.
  • The new .dock-panel rules set touch-action: none via a class and also via a global [role="separator"][aria-orientation="vertical"] selector; consider consolidating this to a single approach to avoid redundant styling and make it clearer which elements are intended to be non-scrollable.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The resizable separator mixes `role="separator"` with slider-like `aria-valuemin/max/now` and keyboard behavior; consider either switching to `role="slider"` or simplifying the ARIA to match separator semantics so assistive tech interprets it correctly.
- In the resize implementation you both call `setPointerCapture` on the handle and attach global `pointermove/pointerup` listeners on `document`; you can likely simplify this by relying on pointer capture and handling events on the element itself to avoid the extra global listeners and cleanup complexity.
- The new `.dock-panel` rules set `touch-action: none` via a class and also via a global `[role="separator"][aria-orientation="vertical"]` selector; consider consolidating this to a single approach to avoid redundant styling and make it clearer which elements are intended to be non-scrollable.

## Individual Comments

### Comment 1
<location path="src/components/ChatPanel.tsx" line_range="234" />
<code_context>
               className="md:hidden p-1.5 rounded-lg text-white hover:bg-white/20"
             >
-     
+              <X size={16} aria-hidden="true" />
             </button>
           )}
</code_context>
<issue_to_address>
**issue (bug_risk):** Close button icon is now inaccessible to screen readers without an accessible name.

With the icon set to `aria-hidden="true"` and no visible text, this button no longer has an accessible name for screen readers. Please add an explicit label (e.g. `aria-label="Close chat"`) to the `<button>` so its purpose is announced to assistive technologies.
</issue_to_address>

### Comment 2
<location path="src/components/panels/DockPanel.tsx" line_range="89" />
<code_context>
-      className="relative flex flex-col bg-white border-l border-gray-200 shrink-0 h-full"
-      style={{ width, minWidth: def.minWidth, maxWidth: def.maxWidth }}
+      className="dock-panel relative flex flex-col bg-white border-l border-gray-200 shrink-0 h-full max-md:fixed max-md:inset-0 max-md:z-40"
+      style={{ width, minWidth: def.minWidth, maxWidth: `min(${def.maxWidth}px, calc(100vw - 360px))` }}
     >
       {/* Resize handle (left edge) */}
</code_context>
<issue_to_address>
**suggestion:** Inline `maxWidth` uses a string expression while `width` and `minWidth` are numbers; consider consistency and edge-case behavior.

Because `width`/`minWidth` are numeric and `maxWidth` is now a CSS expression string, the effective clamping is split between JS and CSS, which can obscure how `setPanelWidth` interacts with the viewport limit. It would be safer to enforce the viewport constraint in the JS sizing logic (so `width` never exceeds the true max) or centralize the calculation, ensuring the rendered width and ARIA `max` stay aligned.

Suggested implementation:

```typescript
  if (!isOpen) return null

  const viewportMaxWidth =
    typeof window !== 'undefined' ? Math.max(0, window.innerWidth - 360) : def.maxWidth
  const effectiveMaxWidth = Math.min(def.maxWidth, viewportMaxWidth)

  return (
    <div
      className="dock-panel relative flex flex-col bg-white border-l border-gray-200 shrink-0 h-full max-md:fixed max-md:inset-0 max-md:z-40"
      style={{ width, minWidth: def.minWidth, maxWidth: effectiveMaxWidth }}
    >

```

```typescript
        aria-valuemin={def.minWidth}
        aria-valuemax={effectiveMaxWidth}
        aria-valuenow={width}
        tabIndex={0}

```

To fully align behavior with this change:
1. Any logic that updates `width` (e.g. resize handlers or `setPanelWidth`) should clamp the new width to `effectiveMaxWidth` rather than `def.maxWidth`, so the JS state never exceeds the viewport-aware limit.
2. If the component is rendered in an environment where `window` may not be available (SSR), ensure that the initial `width` value is also safe relative to `effectiveMaxWidth` or revalidated on the client after mount.
3. If there are ARIA or DOM attributes elsewhere that reference `def.maxWidth`, consider updating them to use `effectiveMaxWidth` for consistency with the actual rendered width.
</issue_to_address>

Fix all in Cursor


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/components/ChatPanel.tsx
Comment thread src/components/panels/DockPanel.tsx Outdated

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/ChatPanel.tsx (1)

228-235: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Add an accessible name to the mobile close button.

Because the only child is aria-hidden, this button has no accessible name for screen-reader users. Add aria-label="Close assistant" (and optionally a matching title) to preserve the close action for all users.

🤖 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/components/ChatPanel.tsx` around lines 228 - 235, Add an accessible name
to the mobile close button rendered in ChatPanel by adding the requested “Close
assistant” label to the button containing the aria-hidden X icon. Keep the
existing onCloseMobile behavior and styling unchanged.
🤖 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/components/panels/DockPanel.tsx`:
- Around line 34-36: Update DockPanel resize logic to derive a
viewport-effective maximum width, capped by both the panel definition and
available viewport space. Use this effective maximum in resizeBy, End-key
handling, and all related ARIA width/min/max values so stored, announced, and
rendered widths remain consistent; preserve the existing minimum-width behavior.

In `@src/index.css`:
- Around line 236-241: Update the prefers-reduced-motion override in the global
*, *::before, *::after rule to set animation-iteration-count: 1 !important
alongside the existing animation-duration override, ensuring infinite animations
run only once.

---

Outside diff comments:
In `@src/components/ChatPanel.tsx`:
- Around line 228-235: Add an accessible name to the mobile close button
rendered in ChatPanel by adding the requested “Close assistant” label to the
button containing the aria-hidden X icon. Keep the existing onCloseMobile
behavior and styling unchanged.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 16256d60-6c8d-4c3a-a9da-8b4ac085ca02

📥 Commits

Reviewing files that changed from the base of the PR and between 95520e7 and d6aa540.

📒 Files selected for processing (5)
  • src/components/ChatPanel.tsx
  • src/components/panels/DockPanel.tsx
  • src/components/panels/panelTypes.ts
  • src/components/panels/panelTypes.tsx
  • src/index.css
💤 Files with no reviewable changes (1)
  • src/components/panels/panelTypes.ts

Comment thread src/components/panels/DockPanel.tsx Outdated
Comment thread src/index.css
Comment on lines +236 to +241
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
scroll-behavior: auto !important;
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
}

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Stop infinite animations under reduced-motion preference.

Shortening duration alone leaves animation-iteration-count: infinite intact, causing looping animations to cycle at 0.01ms. Set animation-iteration-count: 1 !important in this override.

Proposed fix
 `@media` (prefers-reduced-motion: reduce) {
   *, *::before, *::after {
     scroll-behavior: auto !important;
     transition-duration: 0.01ms !important;
     animation-duration: 0.01ms !important;
+    animation-iteration-count: 1 !important;
   }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
scroll-behavior: auto !important;
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
}
`@media` (prefers-reduced-motion: reduce) {
*, *::before, *::after {
scroll-behavior: auto !important;
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
}
🤖 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/index.css` around lines 236 - 241, Update the prefers-reduced-motion
override in the global *, *::before, *::after rule to set
animation-iteration-count: 1 !important alongside the existing
animation-duration override, ensuring infinite animations run only once.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR improves the spreadsheet-first workspace by making docked tools behave more predictably across breakpoints, adding accessible resize interactions for docked panels, and migrating panel definitions to richer metadata (icons + sizing constraints).

Changes:

  • Added responsive layout constraints so docked panels don’t float over / overly compress the spreadsheet, and become full-screen on phones.
  • Implemented pointer + keyboard-accessible resizing for docked panels (ARIA separator semantics + key handling).
  • Replaced string/emoji-based panel type definitions with a React/icon-based panelTypes module including width constraints.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/index.css Adds spreadsheet main min-width rules, mobile dock panel full-screen behavior, separator touch behavior, and reduced-motion CSS overrides.
src/components/panels/panelTypes.tsx Introduces React-based panel metadata (lucide icons + sizing constraints).
src/components/panels/panelTypes.ts Removes the old emoji/string-based panel metadata module.
src/components/panels/DockPanel.tsx Updates dock panel resizing to pointer events, adds keyboard resizing + ARIA attributes, and adjusts layout for mobile/fullscreen docking.
src/components/ChatPanel.tsx Refines header copy and replaces the mobile close glyph with a lucide icon.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 229 to 233
<button
type="button"
onClick={onCloseMobile}
className="md:hidden p-1.5 rounded-lg text-white hover:bg-white/20"
>
Comment thread src/index.css
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Note

Docstrings generation - SKIPPED
Skipped regeneration as there are no new commits. Docstrings already generated for this pull request at #14.

Docstrings generation was requested by @Ocean82.

* #13 (comment)

The following files were modified:

* `src/components/ChatPanel.tsx`
* `src/components/panels/DockPanel.tsx`
* `src/components/panels/panelTypes.tsx`

@Ocean82 Ocean82 left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

reviewed

Commented in CodeRabbit Change Stack

Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>

@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: 3

🤖 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/components/panels/DockPanel.tsx`:
- Around line 72-79: Add unmount cleanup for the resize drag state in
DockPanel’s handleResizeEnd-related effect or component cleanup: clear
resizeStartRef and reset document.body.style.cursor and
document.body.style.userSelect to empty values when the panel unmounts, while
preserving the existing pointer-up/cancel cleanup.
- Around line 106-110: Update the resize control’s accessibility semantics in
the DockPanel slider markup: change aria-orientation to horizontal so it matches
the width-changing, Left/Right keyboard behavior, while preserving the existing
slider role and value attributes.
- Around line 42-48: Validate and normalize the persisted value used by
storedWidth in DockPanel before passing it to Math.min/Math.max: accept only
finite numeric widths and fall back to def.defaultWidth otherwise. Keep the
existing clamping and useEffect persistence flow, ensuring corrupted values
cannot produce NaN or repeated setPanelWidth calls.
🪄 Autofix (Beta)

❌ Autofix failed (check again to retry)

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 Plus

Run ID: c96bcf8c-5ab2-4214-90ea-c7de60d5b126

📥 Commits

Reviewing files that changed from the base of the PR and between d6aa540 and c41bf4c.

📒 Files selected for processing (3)
  • src/components/ChatPanel.tsx
  • src/components/panels/DockPanel.tsx
  • src/index.css
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/ChatPanel.tsx

Comment on lines +42 to +48
const storedWidth = panelWidths[panelId] ?? def.defaultWidth
const width = Math.min(effectiveMaxWidth, Math.max(def.minWidth, storedWidth))
const isOpen = activePanel === panelId

useEffect(() => {
if (storedWidth !== width) setPanelWidth(panelId, width)
}, [panelId, setPanelWidth, storedWidth, width])

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Validate persisted panel widths before arithmetic.

src/store/slices/uiSlice.ts deserializes panelWidths without validating each value. A stale or corrupted entry can make width become NaN; this also makes storedWidth !== width permanently true because NaN !== NaN, potentially causing repeated setPanelWidth calls. Normalize values to finite numbers with a default fallback before clamping.

Proposed fix
-  const storedWidth = panelWidths[panelId] ?? def.defaultWidth
+  const rawStoredWidth = panelWidths[panelId]
+  const storedWidth =
+    typeof rawStoredWidth === 'number' && Number.isFinite(rawStoredWidth)
+      ? rawStoredWidth
+      : def.defaultWidth
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const storedWidth = panelWidths[panelId] ?? def.defaultWidth
const width = Math.min(effectiveMaxWidth, Math.max(def.minWidth, storedWidth))
const isOpen = activePanel === panelId
useEffect(() => {
if (storedWidth !== width) setPanelWidth(panelId, width)
}, [panelId, setPanelWidth, storedWidth, width])
const rawStoredWidth = panelWidths[panelId]
const storedWidth =
typeof rawStoredWidth === 'number' && Number.isFinite(rawStoredWidth)
? rawStoredWidth
: def.defaultWidth
const width = Math.min(effectiveMaxWidth, Math.max(def.minWidth, storedWidth))
const isOpen = activePanel === panelId
useEffect(() => {
if (storedWidth !== width) setPanelWidth(panelId, width)
}, [panelId, setPanelWidth, storedWidth, width])
🤖 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/components/panels/DockPanel.tsx` around lines 42 - 48, Validate and
normalize the persisted value used by storedWidth in DockPanel before passing it
to Math.min/Math.max: accept only finite numeric widths and fall back to
def.defaultWidth otherwise. Keep the existing clamping and useEffect persistence
flow, ensuring corrupted values cannot produce NaN or repeated setPanelWidth
calls.

Comment on lines +72 to +79
const handleResizeEnd = useCallback((e: React.PointerEvent<HTMLDivElement>) => {
resizeStartRef.current = null
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
e.currentTarget.releasePointerCapture(e.pointerId)
}
document.body.style.cursor = ''
document.body.style.userSelect = ''
}, [])

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Clean up global drag styles on unmount.

If the panel unmounts during an active drag, document.body retains cursor: col-resize and user-select: none because cleanup only runs on pointer-up/cancel. Add an unmount cleanup that clears resizeStartRef and restores these styles.

Proposed fix
+  useEffect(() => {
+    return () => {
+      resizeStartRef.current = null
+      document.body.style.cursor = ''
+      document.body.style.userSelect = ''
+    }
+  }, [])
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleResizeEnd = useCallback((e: React.PointerEvent<HTMLDivElement>) => {
resizeStartRef.current = null
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
e.currentTarget.releasePointerCapture(e.pointerId)
}
document.body.style.cursor = ''
document.body.style.userSelect = ''
}, [])
useEffect(() => {
return () => {
resizeStartRef.current = null
document.body.style.cursor = ''
document.body.style.userSelect = ''
}
}, [])
const handleResizeEnd = useCallback((e: React.PointerEvent<HTMLDivElement>) => {
resizeStartRef.current = null
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
e.currentTarget.releasePointerCapture(e.pointerId)
}
document.body.style.cursor = ''
document.body.style.userSelect = ''
}, [])
🤖 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/components/panels/DockPanel.tsx` around lines 72 - 79, Add unmount
cleanup for the resize drag state in DockPanel’s handleResizeEnd-related effect
or component cleanup: clear resizeStartRef and reset document.body.style.cursor
and document.body.style.userSelect to empty values when the panel unmounts,
while preserving the existing pointer-up/cancel cleanup.

Comment on lines +106 to +110
role="slider"
aria-orientation="vertical"
aria-label={`Resize ${def.label} panel`}
onMouseDown={handleResizeStart}
className="absolute top-0 left-0 w-1.5 h-full cursor-col-resize z-10 group hover:bg-blue-400/30 active:bg-blue-500/40"
aria-valuemin={def.minWidth}
aria-valuemax={effectiveMaxWidth}

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and inspect the relevant component and its keyboard handling semantics.
if [ -f src/components/panels/DockPanel.tsx ]; then
  printf '--- DockPanel outline ---\n'
  ast-grep outline src/components/panels/DockPanel.tsx --view compact 2>/dev/null || true
  printf '\n--- DockPanel relevant lines 1-180 ---\n'
  sed -n '1,180p' src/components/panels/DockPanel.tsx
else
  fd -a DockPanel.tsx .
fi

printf '\n--- searches for DockPanel resizing controls ---\n'
rg -n "role=\"slider\"|aria-orientation|KeyDown|ArrowLeft|ArrowRight|separator|resize" src/components/panels/DockPanel.tsx src || true

Repository: Ocean82/smartshit

Length of output: 246


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "pwd=$(pwd)"
git ls-files | grep -F 'src/components/panels/DockPanel.tsx' || true
ls -la src/components/panels/DockPanel.tsx 2>/dev/null || true

if [ -f src/components/panels/DockPanel.tsx ]; then
  echo "--- DockPanel outline ---"
  ast-grep outline src/components/panels/DockPanel.tsx --view compact 2>/dev/null || true
  echo
  echo "--- DockPanel relevant lines 1-180 ---"
  sed -n '1,180p' src/components/panels/DockPanel.tsx
else
  echo "--- fallback location search ---"
  fd -a DockPanel.tsx . 2>/dev/null || true
fi

echo
echo "--- searches for DockPanel resizing controls ---"
rg -n 'role="slider"|aria-orientation|onKeyDown|KeyboardEvent|ArrowLeft|ArrowRight|separator|resize' src/components/panels/DockPanel.tsx src || true

Repository: Ocean82/smartshit

Length of output: 15132


Make the resize slider’s aria orientation match the horizontal resize behavior.

The vertical divider control changes width and responds to Left/Right keys, but exposes aria-orientation="vertical". Use aria-orientation="horizontal" to match the change direction, or replace the slider role with role="separator" if vertical-divider semantics are intended.

🤖 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/components/panels/DockPanel.tsx` around lines 106 - 110, Update the
resize control’s accessibility semantics in the DockPanel slider markup: change
aria-orientation to horizontal so it matches the width-changing, Left/Right
keyboard behavior, while preserving the existing slider role and value
attributes.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 1 file(s) based on 1 unresolved review comment.

Files modified:

  • package-lock.json

Commit: a273fc413f983c29a9227f9f77351d1bb579e070

The changes have been pushed to the arena/019f987a-smartshit branch.

Time taken: 1m 51s

Fixed 1 file(s) based on 1 unresolved review comment.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

⚠️ Branch updated during autofix.

The branch was updated while autofix was in progress. Please try again.

📝 Add docstrings to `arena/019f987a-smartshit`
@Ocean82
Ocean82 merged commit f79bb2b into main Jul 25, 2026
4 checks passed
@Ocean82
Ocean82 deleted the arena/019f987a-smartshit branch July 25, 2026 10:34
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.

2 participants