fix(intelligence): make page content scrollable inside Brain card (#4332)

This commit is contained in:
Cyrus Gray
2026-06-30 17:00:41 +05:30
committed by GitHub
parent d1d3cd6562
commit ca2c93e270
3 changed files with 33 additions and 8 deletions
+6
View File
@@ -328,3 +328,9 @@ Quick reference for anyone starting with Claude on this project. Updated by the
- **Queue self-heal retries transient failures only** — `memory_queue/scheduler.rs` calls `store::requeue_transient_failed` every 3h (excludes `failure_class = 'unrecoverable'` so bad keys/budget don't retry-loop). Full reset stays manual via `memory_tree_retry_failed` RPC.
- **`openhuman.memory_sources_reconcile` RPC** — Reports per-scope raw coverage `{total_raw_files, covered, pending}`; `execute: true` spawns background incremental rebuild. Same reconcile auto-runs after every sync via `check_and_rebuild_tree`.
- **L0 seal gate is token-only by design** — `should_seal` has NO sibling-count fallback at L0 (docs used to lie about this); small buffers seal via the 3-hourly `flush_stale` path. L≥1 gates on `SUMMARY_FANOUT` (10) — an L1 buffer holding <10 summaries is healthy, not stuck.
## Intelligence page scroll ownership (#4267)
- **`app/src/pages/Intelligence.tsx` is rendered ONLY by `Brain.tsx`** (`/settings/intelligence` redirects to `/brain?tab=intelligence`), inside a card with `h-full overflow-hidden` (`Brain.tsx` ~line 255). A code comment there asserts the embedded panels "own their own scroll directly" — true for the sibling `PanelPage`/`PanelScaffold` panels (MemoryDataPanel etc.), but Intelligence previously returned a bare `<div className="z-10 relative">` with NO height/scroll, so its content overflowed the card and was clipped with no scrollbar.
- **Fix pattern (matches `PanelPage`)**: root `flex h-full min-h-0 flex-col` → pinned `SettingsHeader` wrapper (`flex-shrink-0`) → body `min-h-0 flex-1 overflow-y-auto` wrapping ChipTabs + the content card. `ToastContainer`/`ConfirmationModal` stay as siblings OUTSIDE the scroll region. The scroll body carries `data-testid="intelligence-scroll"` for the regression test.
- **Gotcha for any panel embedded in Brain's Knowledge/Memory card**: it must own its own vertical scroll (the card is `overflow-hidden`). Don't rely on a parent scroll — there isn't one.
+17 -8
View File
@@ -201,15 +201,24 @@ export default function Intelligence({ tabParamKey = 'tab' }: IntelligenceProps
const activeTabDef = tabs.find(tab => tab.id === activeTab);
return (
<div className="z-10 relative">
<SettingsHeader
title={t('settings.developerMenu.intelligence.title')}
showBackButton={true}
onBack={navigateBack}
breadcrumbs={breadcrumbs}
/>
// Rendered inside Brain's `h-full overflow-hidden` card, so this panel must
// own its own scroll (like the sibling PanelPage panels) — otherwise its
// content overflows the card and is clipped with no scrollbar (#4267). A
// flex column pins the header (`flex-shrink-0`) and gives the body the one
// vertical scroll (`min-h-0 flex-1 overflow-y-auto`).
<div className="z-10 relative flex h-full min-h-0 flex-col">
<div className="flex-shrink-0">
<SettingsHeader
title={t('settings.developerMenu.intelligence.title')}
showBackButton={true}
onBack={navigateBack}
breadcrumbs={breadcrumbs}
/>
</div>
<div className="p-4 space-y-4">
<div
className="min-h-0 flex-1 overflow-y-auto p-4 space-y-4"
data-testid="intelligence-scroll">
<ChipTabs<IntelligenceTab>
items={tabs.map(tab => ({
id: tab.id,
@@ -97,4 +97,14 @@ describe('Intelligence URL-backed tab', () => {
expect(screen.getByTestId('tab-council')).toBeInTheDocument();
expect(screen.getByText('selected:council')).toBeInTheDocument();
});
// Regression for #4267: rendered inside Brain's `overflow-hidden` card, the
// panel must own a vertical scroll region that wraps the tab content, or the
// content is clipped with no scrollbar.
it('wraps the tab content in an overflow-y-auto scroll container', () => {
renderAt('/intelligence');
const scroll = screen.getByTestId('intelligence-scroll');
expect(scroll).toHaveClass('overflow-y-auto');
expect(scroll).toContainElement(screen.getByTestId('tab-tasks'));
});
});