Skip to content

feat: Add resizable and collapsible left panel to workspace page#631

Open
jeremyeder wants to merge 1 commit intomainfrom
ambient/session-1771102471
Open

feat: Add resizable and collapsible left panel to workspace page#631
jeremyeder wants to merge 1 commit intomainfrom
ambient/session-1771102471

Conversation

@jeremyeder
Copy link
Collaborator

It looks mostly similar to the Sessions page version. Good enough anyway.

Implements left panel improvements for the workspace/sessions list page:

  • Users can hide the sidebar by clicking "Hide sidebar" button at the bottom
  • Users can show the sidebar by clicking floating chevron button on left edge
  • Users can resize the sidebar width by dragging the resize handle
  • Panel visibility and width preferences are persisted to localStorage

Follows the same pattern as the session detail page implementation.

Fixes: RHOAIENG-45393

Implements left panel improvements for the workspace/sessions list page:
- Users can hide the sidebar by clicking "Hide sidebar" button at the bottom
- Users can show the sidebar by clicking floating chevron button on left edge
- Users can resize the sidebar width by dragging the resize handle
- Panel visibility and width preferences are persisted to localStorage

Follows the same pattern as the session detail page implementation.

Fixes: RHOAIENG-45393

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

github-actions bot commented Feb 15, 2026

Claude Code Review

Summary

This PR adds resizable and collapsible left panel functionality to the workspace page (/projects/[name]), following the same pattern as the session detail page. The implementation provides users with controls to hide/show the sidebar and resize its width, with preferences persisted to localStorage.

Overall Assessment: The implementation is solid and follows established patterns, but there are a few minor improvements that could enhance code quality and user experience.

Issues by Severity

🚫 Blocker Issues

None - the code is ready to merge from a blocking perspective.

🔴 Critical Issues

None

🟡 Major Issues

1. SSR/Hydration Warning Risk

  • Location: Lines 39-43, 184
  • Issue: The defaultSize prop on line 184 depends on leftPanelVisible state, which is initialized from localStorage. This could cause hydration mismatches if the server-rendered value differs from the client's localStorage value.
  • Impact: Console warnings in development, potential UI flickering on first load
  • Recommendation:
    // Line 184 - Use a static defaultSize instead
    <ResizablePanel
      id="workspace-main-panel"
      order={2}
      defaultSize={80}  // Static default, let autoSaveId handle persistence
      minSize={50}
    >
    The autoSaveId="workspace-layout" on line 124 already handles persistence, so the dynamic defaultSize is unnecessary.

2. Inconsistent localStorage Key Naming

  • Location: Lines 41, 47
  • Issue: Uses workspace-left-panel-visible while the session detail page uses session-left-panel-visible. The autoSaveId uses workspace-layout.
  • Impact: Inconsistent naming convention across the codebase
  • Recommendation: Consider aligning with a consistent pattern like {page}-left-panel-visible (already correct) and document this pattern in frontend context files.

🔵 Minor Issues

1. Missing Accessibility Attributes

  • Location: Lines 109-117 (floating show button)
  • Issue: The floating button has a title attribute but missing proper ARIA labels
  • Recommendation:
    <Button
      variant="outline"
      size="sm"
      className="fixed left-2 top-1/2 -translate-y-1/2 z-30 h-8 w-8 p-0 rounded-full shadow-md"
      onClick={() => setLeftPanelVisible(true)}
      aria-label="Show sidebar"  // Add this
    >
      <ChevronRight className="h-4 w-4" />
    </Button>

2. Magic Number for Panel Sizes

  • Location: Lines 132-134
  • Issue: Panel size percentages (20%, 15%, 35%) are hardcoded without explanation
  • Recommendation: Extract to named constants at the top of the file:
    const PANEL_SIZES = {
      LEFT_DEFAULT: 20,
      LEFT_MIN: 15,
      LEFT_MAX: 35,
      MAIN_MIN: 50,
    } as const;

3. Duplicate Pattern with Session Detail Page

  • Issue: This implementation duplicates the panel collapse/resize logic from the session detail page
  • Impact: Future maintenance burden - changes need to be applied in two places
  • Recommendation: Consider extracting this pattern to a reusable hook:
    // hooks/use-collapsible-panel.ts
    function useCollapsiblePanel(storageKey: string) {
      const [isVisible, setIsVisible] = useState(() => {
        if (typeof window === 'undefined') return true;
        const saved = localStorage.getItem(storageKey);
        return saved === null ? true : saved === 'true';
      });
    
      useEffect(() => {
        localStorage.setItem(storageKey, String(isVisible));
      }, [isVisible, storageKey]);
    
      return { isVisible, setIsVisible };
    }
    This would reduce duplication and ensure consistency.

Positive Highlights

Follows Established Patterns: Correctly reuses the pattern from the session detail page, maintaining consistency across the application

Uses Shadcn UI Components: Properly leverages ResizablePanelGroup, ResizablePanel, and ResizableHandle from the UI library

SSR-Safe localStorage Access: Correctly handles typeof window === 'undefined' check on line 40

Proper State Persistence: Uses useEffect to sync state to localStorage (lines 46-48)

Good UX Design:

  • Floating chevron button appears when panel is hidden (lines 108-118)
  • Hide button at the bottom of the sidebar (lines 164-174)
  • Visual feedback on resize handle with hover effect (line 177)

Type Safety: Properly typed component with no any types

Clean Code Structure: Component remains under 200 lines (199 lines), well-organized with clear sections

Accessibility: Uses semantic HTML and ARIA-friendly Shadcn components

Recommendations

Priority Order:

  1. Merge as-is - No blocking issues, code is production-ready
  2. 🟡 Follow-up PR: Fix defaultSize hydration issue (5-minute fix)
  3. 🔵 Future improvement: Extract to reusable hook to reduce duplication with session detail page
  4. 🔵 Nice-to-have: Add ARIA labels and extract magic numbers to constants

Pre-Commit Checklist Validation

Checking against frontend standards from CLAUDE.md:

  • ✅ Zero any types
  • ✅ All UI uses Shadcn components
  • ✅ All data operations use React Query (useProject)
  • ✅ Component under 200 lines (199 lines)
  • ✅ Single-use components would be colocated (N/A - no new components)
  • ✅ Buttons have appropriate states
  • ✅ Nested page has breadcrumbs (lines 86-92)
  • ✅ All types use type instead of interface (line 24)

Verdict: ✅ APPROVED - Well-implemented feature that follows repository standards. Minor improvements suggested but not blocking.


Note: This review was generated using the memory system context files loaded from:

  • .claude/context/frontend-development.md
  • .claude/context/security-standards.md
  • .claude/patterns/react-query-usage.md
  • CLAUDE.md

🔍 View AI decision process (logs available for 90 days)

📋 View memory system files loaded (click to expand)

What Amber Loaded for Code Review

Amber automatically loaded these repository standards from the memory system:

  1. CLAUDE.md - Master project instructions, development standards
  2. backend-development.md - Go backend, K8s integration patterns
  3. frontend-development.md - NextJS, Shadcn UI, React Query patterns
  4. security-standards.md - Auth, RBAC, token handling
  5. k8s-client-usage.md - User token vs service account patterns
  6. error-handling.md - Consistent error patterns
  7. react-query-usage.md - Data fetching patterns

Impact: This review used your repository's specific code quality standards, security patterns, and best practices from the memory system (PRs #359, #360) - not just generic code review guidelines.

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