fix(web): contain pipeline debug scrolling

This commit is contained in:
RockChinQ
2026-08-25 12:03:43 +08:00
parent e70a0d3f01
commit f65cca3f40
3 changed files with 26 additions and 12 deletions
@@ -144,7 +144,7 @@ export default function DebugDialog({
new Set(), new Set(),
); );
const [streamOutput, setStreamOutput] = useState(true); const [streamOutput, setStreamOutput] = useState(true);
const messagesEndRef = useRef<HTMLDivElement>(null); const scrollAreaRef = useRef<HTMLDivElement>(null);
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const popoverRef = useRef<HTMLDivElement>(null); const popoverRef = useRef<HTMLDivElement>(null);
const fileInputRef = useRef<HTMLInputElement>(null); const fileInputRef = useRef<HTMLInputElement>(null);
@@ -152,17 +152,14 @@ export default function DebugDialog({
const isInitializingRef = useRef<boolean>(false); const isInitializingRef = useRef<boolean>(false);
const scrollToBottom = useCallback(() => { const scrollToBottom = useCallback(() => {
// Use setTimeout to ensure scroll happens after DOM update
setTimeout(() => { setTimeout(() => {
const scrollArea = document.querySelector('.scroll-area') as HTMLElement; const viewport = scrollAreaRef.current?.querySelector<HTMLElement>(
if (scrollArea) { '[data-slot="scroll-area-viewport"]',
scrollArea.scrollTo({ );
top: scrollArea.scrollHeight, viewport?.scrollTo({
behavior: 'smooth', top: viewport.scrollHeight,
}); behavior: 'smooth',
} });
// Also ensure messagesEndRef scrolls into view
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
}, 0); }, 0);
}, []); }, []);
@@ -843,6 +840,7 @@ export default function DebugDialog({
<div className="flex-1 flex flex-col w-[10rem] h-full min-h-0"> <div className="flex-1 flex flex-col w-[10rem] h-full min-h-0">
<ScrollArea <ScrollArea
ref={scrollAreaRef}
className={cn( className={cn(
'flex-1 overflow-y-auto min-h-0 scroll-area', 'flex-1 overflow-y-auto min-h-0 scroll-area',
compact ? 'p-3' : 'p-6', compact ? 'p-3' : 'p-6',
@@ -934,7 +932,6 @@ export default function DebugDialog({
</div> </div>
)) ))
)} )}
<div ref={messagesEndRef} />
</div> </div>
</ScrollArea> </ScrollArea>
@@ -27,6 +27,12 @@ test.describe('processor detail workbench', () => {
expect(debugBox!.x).toBeLessThan(configBox!.x); expect(debugBox!.x).toBeLessThan(configBox!.x);
expect(configBox!.width).toBeGreaterThan(debugBox!.width); expect(configBox!.width).toBeGreaterThan(debugBox!.width);
const appShell = page.locator('[class*="group/sidebar-wrapper"]');
await expect
.poll(() => appShell.evaluate((element) => element.scrollTop))
.toBe(0);
expect(debugBox!.y).toBeGreaterThanOrEqual(0);
const flow = configPanel.locator('ol'); const flow = configPanel.locator('ol');
await expect(flow.getByRole('button').nth(0)).toContainText( await expect(flow.getByRole('button').nth(0)).toContainText(
'Bindable Event Range', 'Bindable Event Range',
@@ -63,6 +69,12 @@ test.describe('processor detail workbench', () => {
expect(debugBox!.x).toBeLessThan(configBox!.x); expect(debugBox!.x).toBeLessThan(configBox!.x);
expect(configBox!.width).toBeGreaterThan(debugBox!.width); expect(configBox!.width).toBeGreaterThan(debugBox!.width);
const appShell = page.locator('[class*="group/sidebar-wrapper"]');
await expect
.poll(() => appShell.evaluate((element) => element.scrollTop))
.toBe(0);
expect(debugBox!.y).toBeGreaterThanOrEqual(0);
const flow = configPanel.locator('ol'); const flow = configPanel.locator('ol');
await expect(flow.getByRole('button').nth(0)).toContainText( await expect(flow.getByRole('button').nth(0)).toContainText(
'Trigger Conditions', 'Trigger Conditions',
@@ -22,6 +22,9 @@ test('agent and pipeline details share the split processor workbench', () => {
const websocketClient = readSource( const websocketClient = readSource(
'src/app/infra/websocket/WebSocketClient.ts', 'src/app/infra/websocket/WebSocketClient.ts',
); );
const pipelineDebug = readSource(
'src/app/home/pipelines/components/debug-dialog/DebugDialog.tsx',
);
assert.match( assert.match(
workbench, workbench,
@@ -42,6 +45,8 @@ test('agent and pipeline details share the split processor workbench', () => {
websocketClient, websocketClient,
/data\.type === 'connected'[\s\S]*this\.reconnectAttempts = 0/, /data\.type === 'connected'[\s\S]*this\.reconnectAttempts = 0/,
); );
assert.match(pipelineDebug, /data-slot="scroll-area-viewport"/);
assert.doesNotMatch(pipelineDebug, /scrollIntoView/);
}); });
test('processor forms expose their primary orchestration flow horizontally', () => { test('processor forms expose their primary orchestration flow horizontally', () => {