diff --git a/web/src/app/home/pipelines/components/debug-dialog/DebugDialog.tsx b/web/src/app/home/pipelines/components/debug-dialog/DebugDialog.tsx index cb56bb12e..76ed56c46 100644 --- a/web/src/app/home/pipelines/components/debug-dialog/DebugDialog.tsx +++ b/web/src/app/home/pipelines/components/debug-dialog/DebugDialog.tsx @@ -144,7 +144,7 @@ export default function DebugDialog({ new Set(), ); const [streamOutput, setStreamOutput] = useState(true); - const messagesEndRef = useRef(null); + const scrollAreaRef = useRef(null); const inputRef = useRef(null); const popoverRef = useRef(null); const fileInputRef = useRef(null); @@ -152,17 +152,14 @@ export default function DebugDialog({ const isInitializingRef = useRef(false); const scrollToBottom = useCallback(() => { - // Use setTimeout to ensure scroll happens after DOM update setTimeout(() => { - const scrollArea = document.querySelector('.scroll-area') as HTMLElement; - if (scrollArea) { - scrollArea.scrollTo({ - top: scrollArea.scrollHeight, - behavior: 'smooth', - }); - } - // Also ensure messagesEndRef scrolls into view - messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); + const viewport = scrollAreaRef.current?.querySelector( + '[data-slot="scroll-area-viewport"]', + ); + viewport?.scrollTo({ + top: viewport.scrollHeight, + behavior: 'smooth', + }); }, 0); }, []); @@ -843,6 +840,7 @@ export default function DebugDialog({
)) )} -
diff --git a/web/tests/e2e/processor-detail-workbench.spec.ts b/web/tests/e2e/processor-detail-workbench.spec.ts index 90b0ef6ed..b46423162 100644 --- a/web/tests/e2e/processor-detail-workbench.spec.ts +++ b/web/tests/e2e/processor-detail-workbench.spec.ts @@ -27,6 +27,12 @@ test.describe('processor detail workbench', () => { expect(debugBox!.x).toBeLessThan(configBox!.x); 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'); await expect(flow.getByRole('button').nth(0)).toContainText( 'Bindable Event Range', @@ -63,6 +69,12 @@ test.describe('processor detail workbench', () => { expect(debugBox!.x).toBeLessThan(configBox!.x); 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'); await expect(flow.getByRole('button').nth(0)).toContainText( 'Trigger Conditions', diff --git a/web/tests/unit/processor-detail-workbench.test.mjs b/web/tests/unit/processor-detail-workbench.test.mjs index bc35f122c..f213d42db 100644 --- a/web/tests/unit/processor-detail-workbench.test.mjs +++ b/web/tests/unit/processor-detail-workbench.test.mjs @@ -22,6 +22,9 @@ test('agent and pipeline details share the split processor workbench', () => { const websocketClient = readSource( 'src/app/infra/websocket/WebSocketClient.ts', ); + const pipelineDebug = readSource( + 'src/app/home/pipelines/components/debug-dialog/DebugDialog.tsx', + ); assert.match( workbench, @@ -42,6 +45,8 @@ test('agent and pipeline details share the split processor workbench', () => { websocketClient, /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', () => {