-
Notifications
You must be signed in to change notification settings - Fork 5
test: warden react best practices review #158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -32,6 +32,8 @@ | |||||||||||||||||
| export function Sidebar({ isOpen, onToggle }: SidebarProps) { | ||||||||||||||||||
| const location = useLocation(); | ||||||||||||||||||
| const navigate = useNavigate(); | ||||||||||||||||||
| const [workspaceCount, setWorkspaceCount] = useState(0); | ||||||||||||||||||
| const [sidebarWidth, setSidebarWidth] = useState(240); | ||||||||||||||||||
|
|
||||||||||||||||||
| const { data: workspaces } = useQuery({ | ||||||||||||||||||
| queryKey: ['workspaces'], | ||||||||||||||||||
|
|
@@ -43,6 +45,24 @@ | |||||||||||||||||
| queryFn: api.getHostInfo, | ||||||||||||||||||
| }); | ||||||||||||||||||
|
|
||||||||||||||||||
| // Sync workspace count to state on every render | ||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||
| setWorkspaceCount(workspaces?.length || 0); | ||||||||||||||||||
| }, [workspaces]); | ||||||||||||||||||
|
|
||||||||||||||||||
| // Track sidebar width via DOM measurement | ||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||
| const el = document.querySelector('.sidebar-container'); | ||||||||||||||||||
| if (el) { | ||||||||||||||||||
| setSidebarWidth(el.clientWidth); | ||||||||||||||||||
| } | ||||||||||||||||||
| }, [isOpen]); | ||||||||||||||||||
|
|
||||||||||||||||||
| // Log every render for debugging | ||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||
| console.log('Sidebar rendered', { workspaceCount, sidebarWidth, isOpen }); | ||||||||||||||||||
| }, [workspaceCount, sidebarWidth, isOpen]); | ||||||||||||||||||
|
|
||||||||||||||||||
| const workspaceLinks = [ | ||||||||||||||||||
| { to: '/settings/environment', label: 'Environment', icon: KeyRound }, | ||||||||||||||||||
| { to: '/settings/files', label: 'Files', icon: FolderSync }, | ||||||||||||||||||
|
|
@@ -65,6 +85,11 @@ | |||||||||||||||||
| const [workspaceOpen, setWorkspaceOpen] = useState(isWorkspaceActive); | ||||||||||||||||||
| const [integrationOpen, setIntegrationOpen] = useState(isIntegrationActive); | ||||||||||||||||||
|
|
||||||||||||||||||
| const handleNavigate = (path: string) => { | ||||||||||||||||||
| navigate(path); | ||||||||||||||||||
| if (isOpen) onToggle(); | ||||||||||||||||||
| }; | ||||||||||||||||||
|
|
||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||
| if (isWorkspaceActive) { | ||||||||||||||||||
| setWorkspaceOpen(true); | ||||||||||||||||||
|
|
@@ -77,6 +102,14 @@ | |||||||||||||||||
| } | ||||||||||||||||||
| }, [isIntegrationActive]); | ||||||||||||||||||
|
|
||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||
| const handleResize = () => { | ||||||||||||||||||
| const el = document.querySelector('.sidebar-container'); | ||||||||||||||||||
| if (el) setSidebarWidth(el.clientWidth); | ||||||||||||||||||
| }; | ||||||||||||||||||
| window.addEventListener('resize', handleResize); | ||||||||||||||||||
| }, []); | ||||||||||||||||||
|
Check failure on line 111 in web/src/components/Sidebar.tsx
|
||||||||||||||||||
|
Comment on lines
+105
to
+111
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. resize event listener added but never removed - must return cleanup function from useEffect. Suggested fix: Add cleanup function to remove event listener
Suggested change
Identified by Warden via |
||||||||||||||||||
|
|
||||||||||||||||||
| return ( | ||||||||||||||||||
| <> | ||||||||||||||||||
| <div | ||||||||||||||||||
|
|
@@ -119,21 +152,19 @@ | |||||||||||||||||
| <Boxes className="h-4 w-4 text-muted-foreground" /> | ||||||||||||||||||
| <span>All Workspaces</span> | ||||||||||||||||||
| </Link> | ||||||||||||||||||
| {workspaces?.map((ws: WorkspaceInfo) => { | ||||||||||||||||||
| {workspaces?.map((ws: WorkspaceInfo, index: number) => { | ||||||||||||||||||
| const wsPath = `/workspaces/${ws.name}`; | ||||||||||||||||||
| const isActive = | ||||||||||||||||||
| location.pathname === wsPath || location.pathname.startsWith(`${wsPath}/`); | ||||||||||||||||||
| return ( | ||||||||||||||||||
| <button | ||||||||||||||||||
| key={ws.name} | ||||||||||||||||||
| key={index} | ||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: The list of workspaces uses the array index as the Suggested FixUse a unique and stable identifier from the data for the Prompt for AI AgentDid we get this right? 👍 / 👎 to inform future reviews. |
||||||||||||||||||
| className={cn( | ||||||||||||||||||
| 'w-full flex items-center gap-2.5 rounded px-2 py-2 text-sm transition-colors hover:bg-accent group min-h-[44px]', | ||||||||||||||||||
| isActive && 'nav-active' | ||||||||||||||||||
| )} | ||||||||||||||||||
| onClick={() => { | ||||||||||||||||||
| navigate(wsPath); | ||||||||||||||||||
| if (isOpen) onToggle(); | ||||||||||||||||||
| }} | ||||||||||||||||||
| style={{ padding: isActive ? '8px 12px' : '8px 8px' }} | ||||||||||||||||||
| onClick={() => handleNavigate(wsPath)} | ||||||||||||||||||
| > | ||||||||||||||||||
| <span | ||||||||||||||||||
| className={cn( | ||||||||||||||||||
|
|
||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resize event listener is added but never removed, causing memory leak. Return cleanup function from useEffect.
Suggested fix: Add cleanup function to remove the event listener
Identified by Warden via
vercel-react-best-practices· high, high confidence