mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-21 07:55:18 +08:00
fix: scope inflight snapshots and compact mobile dashboard (#2650)
This commit is contained in:
@@ -1674,6 +1674,15 @@ class MonitoringService(ExecutionDetailsMixin):
|
||||
}
|
||||
|
||||
async def get_inflight_snapshot(self, context: TenantContext, previous: list[dict] | None = None) -> dict:
|
||||
"""SSE producers outlive the HTTP handler's tenant scope."""
|
||||
workspace = require_workspace_uuid(context)
|
||||
tenant_scope = getattr(self.ap.persistence_mgr, 'tenant_scope', None)
|
||||
if callable(tenant_scope):
|
||||
async with tenant_scope(workspace):
|
||||
return await self._get_inflight_snapshot(context, previous)
|
||||
return await self._get_inflight_snapshot(context, previous)
|
||||
|
||||
async def _get_inflight_snapshot(self, context: TenantContext, previous: list[dict] | None = None) -> dict:
|
||||
"""Bounded Workspace snapshot without dashboard aggregates or token payloads."""
|
||||
from ....utils.inflight import inflight_hub
|
||||
|
||||
|
||||
@@ -759,6 +759,24 @@ async def test_inflight_snapshot_is_scoped_and_keeps_terminal_transition(engine,
|
||||
)
|
||||
session.add(persistence_agent_run.AgentRunEvent(run_id='flight-visible', sequence=1, type='tool.started'))
|
||||
await session.commit()
|
||||
# SSE loaders execute after the HTTP handler's tenant scope has exited.
|
||||
# Cloud persistence rejects implicit execute_async calls in that context.
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
original_execute = service.ap.persistence_mgr.execute_async
|
||||
unscoped_execute = AsyncMock(side_effect=AssertionError('Cloud persistence requires an explicit tenant scope'))
|
||||
|
||||
@asynccontextmanager
|
||||
async def tenant_scope(workspace):
|
||||
assert workspace == WORKSPACE
|
||||
service.ap.persistence_mgr.execute_async = original_execute
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
service.ap.persistence_mgr.execute_async = unscoped_execute
|
||||
|
||||
service.ap.persistence_mgr.tenant_scope = tenant_scope
|
||||
service.ap.persistence_mgr.execute_async = unscoped_execute
|
||||
snapshot = await service.get_inflight_snapshot(WORKSPACE)
|
||||
rows = {r['id']: r for r in snapshot['items']}
|
||||
assert 'flight-secret' not in rows
|
||||
|
||||
@@ -201,7 +201,7 @@ export default function MonitoringFilters({
|
||||
onPipelinesChange([...next]);
|
||||
};
|
||||
return (
|
||||
<div className="grid min-w-0 flex-1 grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-5">
|
||||
<div className="grid min-w-0 flex-1 grid-cols-2 gap-3 lg:grid-cols-5">
|
||||
{/* Bot Filter */}
|
||||
<div className="min-w-0 space-y-1.5">
|
||||
<Label
|
||||
|
||||
@@ -223,7 +223,7 @@ function MonitoringPageContent() {
|
||||
<div className="w-full h-full overflow-y-auto overflow-x-hidden">
|
||||
{/* Filters and Refresh Button - Sticky */}
|
||||
{!error && (
|
||||
<div className="sticky top-0 z-10 -mt-1 pb-5 pt-1 bg-background">
|
||||
<div className="relative z-10 -mt-1 pb-3 pt-1 bg-background lg:sticky lg:top-0 lg:pb-5">
|
||||
<div>
|
||||
<Card className="flex flex-col gap-4 p-4 xl:flex-row xl:items-end">
|
||||
<MonitoringFilters
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { installLangBotApiMocks } from './fixtures/langbot-api';
|
||||
|
||||
for (const width of [375, 430]) {
|
||||
test(`dashboard filters fit mobile ${width}`, async ({ page }) => {
|
||||
await page.setViewportSize({ width, height: 812 });
|
||||
await installLangBotApiMocks(page, { authenticated: true });
|
||||
await page.goto('/home/monitoring');
|
||||
const bot = page.getByRole('combobox', { name: 'Bot', exact: true });
|
||||
await expect(bot).toBeVisible();
|
||||
const grid = bot.locator('..').locator('..');
|
||||
expect(
|
||||
await grid.evaluate(
|
||||
(el) => getComputedStyle(el).gridTemplateColumns.split(' ').length,
|
||||
),
|
||||
).toBe(2);
|
||||
const box = await grid.boundingBox();
|
||||
expect(box!.x).toBeGreaterThanOrEqual(0);
|
||||
expect(box!.x + box!.width).toBeLessThanOrEqual(width);
|
||||
await expect(
|
||||
page.getByRole('button', { name: /Reset Filters/i }),
|
||||
).toBeVisible();
|
||||
await page.screenshot({
|
||||
path: `test-results/dashboard-${width}.png`,
|
||||
fullPage: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user