mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-08-26 12:17:14 +00:00
fix(web): contain pipeline debug scrolling
This commit is contained in:
@@ -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', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user