From 55fca1181434536dcffb2ce9c6c5fa8ac4e497e8 Mon Sep 17 00:00:00 2001 From: Dexploarer <211557447+Dexploarer@users.noreply.github.com> Date: Fri, 27 Feb 2026 22:53:55 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20Memoize=20LogEntryItem=20in?= =?UTF-8?q?=20LogsView=20to=20improve=20rendering=20performance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit addresses a performance bottleneck in the `LogsView` component. Before this change, typing in the search input triggered a re-render of the entire `LogsView` and all of its rendered log entries. When there are many logs, this resulted in significant UI lag on every keystroke. By extracting the log entry row into a new `LogEntryItem` component and wrapping it in `React.memo`, we ensure that only the search query updates while the individual log rows bypass unnecessary re-renders. --- .jules/bolt.md | 3 + apps/app/src/components/LogsView.tsx | 118 +++++++++++++++------------ 2 files changed, 70 insertions(+), 51 deletions(-) create mode 100644 .jules/bolt.md diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 000000000..11aa8b52c --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2024-05-14 - Initial Setup +**Learning:** Initial journal setup. +**Action:** None. \ No newline at end of file diff --git a/apps/app/src/components/LogsView.tsx b/apps/app/src/components/LogsView.tsx index dcc3899fc..bd069366e 100644 --- a/apps/app/src/components/LogsView.tsx +++ b/apps/app/src/components/LogsView.tsx @@ -2,7 +2,7 @@ * Logs view component — logs viewer with filtering. */ -import { useEffect, useMemo, useState } from "react"; +import React, { useEffect, useMemo, useState } from "react"; import { useApp } from "../AppContext"; import type { LogEntry } from "../api-client"; import { formatTime } from "./shared/format"; @@ -18,6 +18,69 @@ const TAG_COLORS: Record = { websocket: { bg: "rgba(20, 184, 166, 0.15)", fg: "rgb(20, 184, 166)" }, }; +/** + * Extracted, memoized log entry item. + * Prevents re-rendering all log lines when the search input value changes. + */ +const LogEntryItem = React.memo(function LogEntryItem({ + entry, +}: { + entry: LogEntry; +}) { + return ( +
+ {/* Timestamp */} + + {formatTime(entry.timestamp, { fallback: "—" })} + + + {/* Level */} + + {entry.level} + + + {/* Source */} + + [{entry.source}] + + + {/* Tag badges */} + + {(entry.tags ?? []).map((t: string) => { + const c = TAG_COLORS[t]; + return ( + + {t} + + ); + })} + + + {/* Message */} + {entry.message} +
+ ); +}); + export function LogsView() { const [searchQuery, setSearchQuery] = useState(""); @@ -163,57 +226,10 @@ export function LogsView() { ) : ( filteredLogs.map((entry: LogEntry) => ( -
- {/* Timestamp */} - - {formatTime(entry.timestamp, { fallback: "—" })} - - - {/* Level */} - - {entry.level} - - - {/* Source */} - - [{entry.source}] - - - {/* Tag badges */} - - {(entry.tags ?? []).map((t: string) => { - const c = TAG_COLORS[t]; - return ( - - {t} - - ); - })} - - - {/* Message */} - {entry.message} -
+ entry={entry} + /> )) )}