Merge branch 'perf/lag': dashboard lag fixes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> # Conflicts: # client/src/components/Sagi/PetSprite.tsx # client/src/components/Sagi/useSagiBrain.ts
This commit is contained in:
@@ -42,6 +42,7 @@
|
||||
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
*/
|
||||
import {
|
||||
memo,
|
||||
useEffect,
|
||||
useId,
|
||||
useMemo,
|
||||
@@ -61,7 +62,7 @@ import { useTheme } from "../../hooks/useTheme";
|
||||
import { terminalThemeFor } from "../../lib/terminalTheme";
|
||||
import { api } from "../../lib/api";
|
||||
import { writeClipboard } from "../../lib/clipboard";
|
||||
import { notePaneFocus, registerPane } from "../../lib/panePaste";
|
||||
import { MENU_CURSOR_ROW, notePaneFocus, registerPane } from "../../lib/panePaste";
|
||||
import { attachImeInput } from "../../lib/imeInput";
|
||||
import { TERMINAL_FONTS, readTerminalFont } from "../../lib/terminalFont";
|
||||
import { FONT_SIZE_EVENT, readTerminalFontSize } from "../../lib/fontSize";
|
||||
@@ -154,9 +155,22 @@ interface TerminalViewProps {
|
||||
/** Take the keyboard when it appears (default). Off for a split pane that
|
||||
* is not the focused one, or keys would land in whichever mounted last. */
|
||||
autoFocus?: boolean;
|
||||
/** Another layer (the pane's chat) covers it. xterm stops drawing only when
|
||||
* its IntersectionObserver says off screen, and a covered terminal is not —
|
||||
* so it is moved out of the viewport with a transform, which keeps its
|
||||
* layout size (no PTY resize; the chat still reads and answers its menus). */
|
||||
covered?: boolean;
|
||||
}
|
||||
|
||||
export function TerminalView({ runId, wsBaseUrl, onExit, autoFocus = true }: TerminalViewProps) {
|
||||
/** Memoized: the Workspace re-renders its pane tree on every lane_update, and
|
||||
* a terminal only cares about its own props (its owner keeps `onExit` stable). */
|
||||
export const TerminalView = memo(function TerminalView({
|
||||
runId,
|
||||
wsBaseUrl,
|
||||
onExit,
|
||||
autoFocus = true,
|
||||
covered = false,
|
||||
}: TerminalViewProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
// Read through a ref: an inline `onExit` from the parent changes identity on
|
||||
// every render, and as an effect dep it would tear the terminal down and
|
||||
@@ -648,16 +662,27 @@ export function TerminalView({ runId, wsBaseUrl, onExit, autoFocus = true }: Ter
|
||||
if (wsRef.current?.readyState === WebSocket.OPEN) wsRef.current.send(data);
|
||||
},
|
||||
// The rows on screen, dim cells (a TUI's placeholder) left out.
|
||||
() => {
|
||||
// `menuOnly` (the chat's 700 ms menu poll): plain text first, and the
|
||||
// cell-by-cell read only when a row could be a menu's cursor row.
|
||||
(menuOnly = false) => {
|
||||
const term = termRef.current;
|
||||
if (!term) return null;
|
||||
const buf = term.buffer.active;
|
||||
if (menuOnly) {
|
||||
let maybe = false;
|
||||
for (let y = 0; y < term.rows && !maybe; y++)
|
||||
maybe = MENU_CURSOR_ROW.test(
|
||||
buf.getLine(buf.baseY + y)?.translateToString(true) ?? ""
|
||||
);
|
||||
if (!maybe) return null;
|
||||
}
|
||||
const rows: string[] = [];
|
||||
const reuse = buf.getNullCell();
|
||||
for (let y = 0; y < term.rows; y++) {
|
||||
const line = buf.getLine(buf.baseY + y);
|
||||
let row = "";
|
||||
for (let x = 0; line && x < line.length; x++) {
|
||||
const cell = line.getCell(x);
|
||||
const cell = line.getCell(x, reuse);
|
||||
// Width 0: the right half of a wide character.
|
||||
if (cell && cell.getWidth() && !cell.isDim()) row += cell.getChars() || " ";
|
||||
}
|
||||
@@ -722,7 +747,12 @@ export function TerminalView({ runId, wsBaseUrl, onExit, autoFocus = true }: Ter
|
||||
onPasteCapture={onPaste}
|
||||
onFocus={() => notePaneFocus(runId)}
|
||||
>
|
||||
<div ref={containerRef} className="h-full w-full" data-testid="terminal-view" />
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="h-full w-full"
|
||||
style={covered ? { transform: "translateX(-300vw)" } : undefined}
|
||||
data-testid="terminal-view"
|
||||
/>
|
||||
<p id={hintId} className="sr-only">
|
||||
{t("terminal.keyboardHint")}
|
||||
</p>
|
||||
@@ -823,4 +853,4 @@ export function TerminalView({ runId, wsBaseUrl, onExit, autoFocus = true }: Ter
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user