Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion LICENSE-3rdparty.csv
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ dev,@types/pako,MIT,Copyright Microsoft Corporation
dev,@types/react,MIT,Copyright Microsoft Corporation
dev,@types/react-dom,MIT,Copyright Microsoft Corporation
dev,@wxt-dev/module-react,MIT,Copyright (c) 2023 Aaron
dev,@types/react-window,MIT,Copyright Microsoft Corporation
dev,@vitejs/plugin-react,MIT,Copyright (c) 2019-present Evan You & Vite Contributors
dev,ajv,MIT,Copyright 2015-2017 Evgeny Poberezkin
dev,browserstack-local,MIT,Copyright 2016 BrowserStack
Expand Down
1 change: 0 additions & 1 deletion test/apps/react-heavy-spa/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
"@types/node": "24.10.4",
"@types/react": "18.3.27",
"@types/react-dom": "18.3.7",
"@types/react-window": "2.0.0",
"@vitejs/plugin-react": "5.1.2",
"globals": "16.5.0",
"typescript": "5.9.3",
Expand Down
120 changes: 65 additions & 55 deletions test/apps/react-heavy-spa/src/components/Infrastructure/HostList.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState, useMemo, useCallback, memo, Dispatch, SetStateAction } from 'react'
import { FixedSizeList as List } from 'react-window'
import { List, RowComponentProps } from 'react-window'
import { Host, HostStatus } from '../../types/data'
import './HostList.css'

Expand Down Expand Up @@ -55,43 +55,62 @@ const SortIcon = memo(
}
)

// Memoized row component for better performance
const HostRow = memo(
Comment on lines -58 to -59
Copy link
Member

Choose a reason for hiding this comment

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

note: This memo wasn't effective in the first place, because onSelect was not wrapped in useCallback. I considered fixing this and keeping the memo, but then:

  • This component is very lightweight, so it doesn't matter
  • The app is called "react-heavy-spa", soo.... maybe we don't need to optimize it too much

({ host, isSelected, onSelect }: { host: Host; isSelected: boolean; onSelect: (host: Host) => void }) => (
<tr className={`host-row ${isSelected ? 'selected' : ''}`} onClick={() => onSelect(host)}>
<td className="host-name">{host.name}</td>
<td>
<span className={`status-badge ${host.status}`}>{host.status}</span>
</td>
<td>
<div className="metric-cell">
<div className="metric-bar">
<div className="metric-fill cpu" style={{ width: `${host.cpu}%` }} />
</div>
<span className="metric-value">{host.cpu}%</span>
</div>
</td>
<td>
<div className="metric-cell">
<div className="metric-bar">
<div className="metric-fill memory" style={{ width: `${host.memory}%` }} />
</div>
<span className="metric-value">{host.memory}%</span>
</div>
</td>
<td>
<div className="metric-cell">
<div className="metric-bar">
<div className="metric-fill disk" style={{ width: `${host.disk}%` }} />
</div>
<span className="metric-value">{host.disk}%</span>
</div>
</td>
<td className="network-cell">{host.network} Mbps</td>
<td className="uptime-cell">{formatUptime(host.uptime)}</td>
</tr>
type HostRowExtraProps = {
filteredAndSortedHosts: Host[]
selectedHost: Host | null
onHostSelect: (host: Host) => void
}

function HostRow({
filteredAndSortedHosts,
index,
style,
selectedHost,
onHostSelect,
}: RowComponentProps<HostRowExtraProps>) {
const host = filteredAndSortedHosts[index]
const isSelected = selectedHost?.id === host.id
return (
<div style={style}>
<table className="host-table" style={{ tableLayout: 'fixed', width: '100%' }}>
<tbody>
<tr className={`host-row ${isSelected ? 'selected' : ''}`} onClick={() => onHostSelect(host)}>
<td className="host-name">{host.name}</td>
<td>
<span className={`status-badge ${host.status}`}>{host.status}</span>
</td>
<td>
<div className="metric-cell">
<div className="metric-bar">
<div className="metric-fill cpu" style={{ width: `${host.cpu}%` }} />
</div>
<span className="metric-value">{host.cpu}%</span>
</div>
</td>
<td>
<div className="metric-cell">
<div className="metric-bar">
<div className="metric-fill memory" style={{ width: `${host.memory}%` }} />
</div>
<span className="metric-value">{host.memory}%</span>
</div>
</td>
<td>
<div className="metric-cell">
<div className="metric-bar">
<div className="metric-fill disk" style={{ width: `${host.disk}%` }} />
</div>
<span className="metric-value">{host.disk}%</span>
</div>
</td>
<td className="network-cell">{host.network} Mbps</td>
<td className="uptime-cell">{formatUptime(host.uptime)}</td>
</tr>
</tbody>
</table>
</div>
)
)
}

const HostList = memo(function HostList({
hosts,
Expand Down Expand Up @@ -248,26 +267,17 @@ const HostList = memo(function HostList({
</thead>
</table>
<div style={{ height: 'calc(100vh - 350px)', overflow: 'auto' }}>
<List
height={Math.min(filteredAndSortedHosts.length * 45 + 10, window.innerHeight - 350)}
itemCount={filteredAndSortedHosts.length}
itemSize={45}
width="100%"
<List<HostRowExtraProps>
rowCount={filteredAndSortedHosts.length}
rowComponent={HostRow}
rowHeight={45}
overscanCount={5}
>
{({ index, style }) => {
const host = filteredAndSortedHosts[index]
return (
<div style={style}>
<table className="host-table" style={{ tableLayout: 'fixed', width: '100%' }}>
<tbody>
<HostRow host={host} isSelected={selectedHost?.id === host.id} onSelect={onHostSelect} />
</tbody>
</table>
</div>
)
rowProps={{
filteredAndSortedHosts,
selectedHost,
onHostSelect,
}}
</List>
/>
</div>
</div>

Expand Down
39 changes: 12 additions & 27 deletions test/apps/react-heavy-spa/src/components/Logs/LogTable.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useMemo, useCallback } from 'react'
import { FixedSizeList as List } from 'react-window'
import { List, RowComponentProps } from 'react-window'
import { LogEntry, LogLevel } from '../../types/data'
import './LogTable.css'

Expand All @@ -9,14 +9,10 @@ interface LogTableProps {
onLogSelect: (log: LogEntry) => void
}

interface LogRowProps {
index: number
style: React.CSSProperties
data?: {
logs: LogEntry[]
selectedLog: LogEntry | null
onLogSelect: (log: LogEntry) => void
}
interface LogRowExtraProps {
logs: LogEntry[]
selectedLog: LogEntry | null
onLogSelect: (log: LogEntry) => void
}

const LOG_LEVEL_COLORS: Record<LogLevel, string> = {
Expand Down Expand Up @@ -64,13 +60,9 @@ function truncateMessage(message: string, maxLength: number = 120): string {
return message.substring(0, maxLength) + '...'
}

function LogRow({ index, style, data }: LogRowProps) {
if (!data) return null

const { logs, selectedLog, onLogSelect } = data
function LogRow({ index, style, logs, selectedLog, onLogSelect }: RowComponentProps<LogRowExtraProps>) {
const log = logs[index]

if (!log) return null
const isSelected = selectedLog?.id === log.id

const handleClick = useCallback(() => {
Expand Down Expand Up @@ -182,20 +174,13 @@ export default function LogTable({ logs, selectedLog, onLogSelect }: LogTablePro
</div>

<div className="log-table-body">
<List<{
logs: LogEntry[]
selectedLog: LogEntry | null
onLogSelect: (log: LogEntry) => void
}>
height={600}
width="100%"
itemCount={logs.length}
itemSize={80}
itemData={itemData}
<List<LogRowExtraProps>
rowCount={logs.length}
rowHeight={80}
rowProps={itemData}
rowComponent={LogRow}
overscanCount={5}
>
{LogRow}
</List>
/>
</div>

<div className="log-table-footer">
Expand Down
48 changes: 0 additions & 48 deletions test/apps/react-heavy-spa/src/react-window.d.ts

This file was deleted.

20 changes: 0 additions & 20 deletions test/apps/react-heavy-spa/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -778,15 +778,6 @@ __metadata:
languageName: node
linkType: hard

"@types/react-window@npm:2.0.0":
version: 2.0.0
resolution: "@types/react-window@npm:2.0.0"
dependencies:
react-window: "npm:*"
checksum: 10c0/4de05bf54c3947a68878f1ddcc019db27811d2390aae2e4eb1ab83bff134d6a2f20318555e06b891234df946528470d7c01e43dff759209ec75c54cbda034acf
languageName: node
linkType: hard

"@types/react@npm:18.3.27":
version: 18.3.27
resolution: "@types/react@npm:18.3.27"
Expand Down Expand Up @@ -1244,7 +1235,6 @@ __metadata:
"@types/node": "npm:24.10.4"
"@types/react": "npm:18.3.27"
"@types/react-dom": "npm:18.3.7"
"@types/react-window": "npm:2.0.0"
"@vitejs/plugin-react": "npm:5.1.2"
globals: "npm:16.5.0"
react: "npm:18.3.1"
Expand Down Expand Up @@ -1708,16 +1698,6 @@ __metadata:
languageName: node
linkType: hard

"react-window@npm:*":
version: 2.2.4
resolution: "react-window@npm:2.2.4"
peerDependencies:
react: ^18.0.0 || ^19.0.0
react-dom: ^18.0.0 || ^19.0.0
checksum: 10c0/4039508429bd4f3e96bb6a9acc8e7253c1185239c19f8a709f85dc90ce64aebde934e588e38dceaf1a533f5b6f67dad7074bdf613e642a5dbc82506dbe14ff9b
languageName: node
linkType: hard

"react-window@npm:2.2.3":
version: 2.2.3
resolution: "react-window@npm:2.2.3"
Expand Down