-
Notifications
You must be signed in to change notification settings - Fork 5
test: warden react best practices review #157
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
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,17 +32,37 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| queryFn: api.listWorkspaces, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { data: hostInfo } = useQuery({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| queryKey: ['hostInfo'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| queryFn: api.getHostInfo, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Sync workspace count to state on every render | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setWorkspaceCount(workspaces?.length || 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, [workspaces]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Check warning on line 51 in web/src/components/Sidebar.tsx
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+49
to
+51
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. 🟠 [3J4-9TC] Unnecessary effect - derive state during render instead (high confidence) workspaceCount is derived from workspaces and should be calculated during render, not in an effect. This causes extra re-renders. Suggested fix: Remove the effect and derive the value during render
Suggested change
Identified by Warden via
Comment on lines
35
to
+51
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. 🟠 [73B-VKA] Redundant state: workspaceCount derived from workspaces (high confidence) workspaceCount duplicates data already available via workspaces?.length. Remove state and use derived value directly. Suggested fix: Remove workspaceCount state and its useEffect. Use workspaces?.length directly where needed. Identified by Warden via |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 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. window resize event listener is added but never removed, causing memory leak and duplicate listeners on component remounts. Suggested fix: Return cleanup function from useEffect to remove event listener
Suggested change
Identified by Warden via
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. 🟠 [REH-E7U] Event listener cleanup missing (high confidence) Resize listener added but never removed, causing memory leak. Return cleanup function from useEffect. Suggested fix: Add cleanup function to remove event listener
Suggested change
Identified by Warden via
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 is never removed, causing memory leak. Add cleanup function to useEffect. Suggested fix: Return cleanup function from useEffect to remove the event listener.
Suggested change
Identified by Warden via
Comment on lines
36
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. 🟠 [A5Z-42X] Redundant state: sidebarWidth measured from DOM (high confidence) sidebarWidth state duplicates CSS-controlled width. Remove state and DOM measurement logic. Suggested fix: Remove sidebarWidth state and both useEffect hooks that measure/update it (lines 54-59 and 105-111). 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 Suggested FixChange 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.
🟠 [MC2-X2M] Unnecessary effect for derived state (high confidence)
workspaceCount is derived from workspaces.length and should be calculated during render, not synced via useEffect which causes extra re-renders.
Suggested fix: Remove useEffect and derive workspaceCount directly during render
Identified by Warden via
vercel-react-best-practices· medium, high confidence