mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-03-17 22:13:08 +00:00
fix: E2E test stability and UI performance improvements (#823)
This commit is contained in:
@@ -119,7 +119,6 @@ export function useBoardEffects({
|
||||
if (featuresFingerprint && !isLoading) {
|
||||
checkAllContexts();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [featuresFingerprint, isLoading, checkContextExists, setFeaturesWithContext]);
|
||||
|
||||
// Re-check context when a feature stops, completes, or errors
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef, useCallback, useState } from 'react';
|
||||
import { useEffect, useRef, useCallback, useState, useMemo } from 'react';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
@@ -54,6 +54,8 @@ export function DevServerLogsPanel({
|
||||
|
||||
const {
|
||||
logs,
|
||||
logsVersion,
|
||||
didTrim,
|
||||
isRunning,
|
||||
isLoading,
|
||||
error,
|
||||
@@ -81,8 +83,9 @@ export function DevServerLogsPanel({
|
||||
return;
|
||||
}
|
||||
|
||||
// If logs got shorter (e.g., cleared), rewrite all
|
||||
if (logs.length < lastLogsLengthRef.current) {
|
||||
// If logs got shorter (e.g., cleared) or buffer was trimmed (content shifted),
|
||||
// do a full rewrite so the terminal stays in sync
|
||||
if (logs.length < lastLogsLengthRef.current || didTrim) {
|
||||
xtermRef.current.write(logs);
|
||||
lastLogsLengthRef.current = logs.length;
|
||||
return;
|
||||
@@ -94,7 +97,7 @@ export function DevServerLogsPanel({
|
||||
xtermRef.current.append(newContent);
|
||||
lastLogsLengthRef.current = logs.length;
|
||||
}
|
||||
}, [logs, worktree?.path]);
|
||||
}, [logs, logsVersion, didTrim, worktree?.path]);
|
||||
|
||||
// Reset when panel opens with a new worktree
|
||||
useEffect(() => {
|
||||
@@ -123,10 +126,19 @@ export function DevServerLogsPanel({
|
||||
}
|
||||
}, []);
|
||||
|
||||
const lineCount = useMemo(() => {
|
||||
if (!logs) return 0;
|
||||
// Count newlines directly instead of allocating a split array
|
||||
let count = 1;
|
||||
for (let i = 0; i < logs.length; i++) {
|
||||
if (logs.charCodeAt(i) === 10) count++;
|
||||
}
|
||||
return count;
|
||||
}, [logs]);
|
||||
|
||||
if (!worktree) return null;
|
||||
|
||||
const formattedStartTime = formatStartedAt(startedAt);
|
||||
const lineCount = logs ? logs.split('\n').length : 0;
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={(isOpen) => !isOpen && onClose()}>
|
||||
|
||||
@@ -5,9 +5,16 @@ import { pathsEqual } from '@/lib/utils';
|
||||
|
||||
const logger = createLogger('DevServerLogs');
|
||||
|
||||
// Maximum log buffer size (characters) - matches server-side MAX_SCROLLBACK_SIZE
|
||||
const MAX_LOG_BUFFER_SIZE = 50_000; // ~50KB
|
||||
|
||||
export interface DevServerLogState {
|
||||
/** The log content (buffered + live) */
|
||||
logs: string;
|
||||
/** Incremented whenever logs content changes (including trim+shift) */
|
||||
logsVersion: number;
|
||||
/** True when the latest append caused head truncation */
|
||||
didTrim: boolean;
|
||||
/** Whether the server is currently running */
|
||||
isRunning: boolean;
|
||||
/** Whether initial logs are being fetched */
|
||||
@@ -52,6 +59,8 @@ interface UseDevServerLogsOptions {
|
||||
export function useDevServerLogs({ worktreePath, autoSubscribe = true }: UseDevServerLogsOptions) {
|
||||
const [state, setState] = useState<DevServerLogState>({
|
||||
logs: '',
|
||||
logsVersion: 0,
|
||||
didTrim: false,
|
||||
isRunning: false,
|
||||
isLoading: false,
|
||||
error: null,
|
||||
@@ -123,6 +132,8 @@ export function useDevServerLogs({ worktreePath, autoSubscribe = true }: UseDevS
|
||||
const clearLogs = useCallback(() => {
|
||||
setState({
|
||||
logs: '',
|
||||
logsVersion: 0,
|
||||
didTrim: false,
|
||||
isRunning: false,
|
||||
isLoading: false,
|
||||
error: null,
|
||||
@@ -136,13 +147,27 @@ export function useDevServerLogs({ worktreePath, autoSubscribe = true }: UseDevS
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Append content to logs
|
||||
* Append content to logs, enforcing a maximum buffer size to prevent
|
||||
* unbounded memory growth and progressive UI lag.
|
||||
*/
|
||||
const appendLogs = useCallback((content: string) => {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
logs: prev.logs + content,
|
||||
}));
|
||||
setState((prev) => {
|
||||
const combined = prev.logs + content;
|
||||
const didTrim = combined.length > MAX_LOG_BUFFER_SIZE;
|
||||
let newLogs = combined;
|
||||
if (didTrim) {
|
||||
const slicePoint = combined.length - MAX_LOG_BUFFER_SIZE;
|
||||
// Find the next newline after the slice point to avoid cutting a line in half
|
||||
const firstNewlineIndex = combined.indexOf('\n', slicePoint);
|
||||
newLogs = combined.slice(firstNewlineIndex > -1 ? firstNewlineIndex + 1 : slicePoint);
|
||||
}
|
||||
return {
|
||||
...prev,
|
||||
logs: newLogs,
|
||||
didTrim,
|
||||
logsVersion: prev.logsVersion + 1,
|
||||
};
|
||||
});
|
||||
}, []);
|
||||
|
||||
// Fetch initial logs when worktreePath changes
|
||||
|
||||
Reference in New Issue
Block a user