fix(app): stabilize sidebar session history#386
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
✅ Files skipped from review due to trivial changes (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughReplaces trim-on-event session behavior with a paginated "pawwork session window" on the client, removes trimming from session.created/updated handlers, preserves session time_updated during execution-context backfill, and exposes the pagination cursor header for CORS. ChangesPawwork Session Window (client)
Backend / Data fixes
Sequence DiagramsequenceDiagram
participant User as User (Browser)
participant Layout as Layout (Client)
participant SDK as GlobalSDK
participant Server as Backend
rect rgba(100, 150, 200, 0.5)
Note over User,Server: Initial window load
User->>Layout: Open Pawwork
Layout->>SDK: experimental.session.list(limit=30)
SDK->>Server: GET /session (limit=30)
Server-->>SDK: [sessions], x-next-cursor (header visible via CORS)
SDK-->>Layout: sessions, hasMore=true
Layout->>Layout: buildPawworkSessionWindow(...)
Layout->>User: Render sessions + "Show more"
end
rect rgba(150, 100, 200, 0.5)
Note over User,Server: New session created
User->>Server: Create session
Server-->>SDK: session.created event
SDK-->>Layout: event listener fires
Layout->>Layout: reconcile/upsert session into windowState (no trimming)
Layout->>User: Sidebar updates with new session
end
rect rgba(200, 150, 100, 0.5)
Note over User,Server: Load more
User->>Layout: Click "Show more"
Layout->>Layout: nextPawworkSessionWindowLimit(30)->60
Layout->>SDK: experimental.session.list(limit=60, cursor=...)
SDK->>Server: GET /session (limit=60, cursor)
Server-->>SDK: [sessions], x-next-cursor
SDK-->>Layout: sessions, hasMore=...
Layout->>Layout: buildPawworkSessionWindow(...)
Layout->>User: Render expanded list
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Review rate limit: 9/10 reviews remaining, refill in 6 minutes. Comment |
There was a problem hiding this comment.
Code Review
This pull request implements a windowed session management system for the Pawwork sidebar, replacing the previous session trimming logic with a paginated approach. Key changes include the introduction of a pawworkSessionWindowState to manage session visibility, new UI components for 'Show more' and search prompts, and backend updates to support pagination headers and preserve session update times during database backfills. Feedback was provided regarding the efficiency of fetching pinned sessions individually, suggesting a bulk fetch API to improve scalability and reduce concurrent network requests.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
packages/opencode/test/session/session.test.ts (1)
268-293: UsetestEffect(...)andit.live(...)for this Effect + live-state test.This test exercises Effect services with live git/filesystem/database state, so it should follow the established pattern in other test files: import
testEffectfromtest/lib/effect.ts, defineconst it = testEffect(...)at the top, and useit.live(...)instead oftest(...)with manualEffect.runPromise(...).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/opencode/test/session/session.test.ts` around lines 268 - 293, Replace the plain Jest test with the project’s Effect-aware pattern: import testEffect from "test/lib/effect.ts" and define const it = testEffect(...) at the top of the file, then change test("backfill preserves legacy session updated time", ...) to it.live("backfill preserves legacy session updated time", async () => { ... }); inside the test body stop calling Effect.runPromise(SessionNs.backfillExecutionContext) directly and instead run the backfill as part of the effect test runtime (i.e., invoke SessionNs.backfillExecutionContext through the it.live/Effect runtime), keeping the rest of the logic (SessionNs.create, Database.use updates, assertions on time_updated, and SessionNs.remove) intact so the test uses the live git/filesystem/database fixtures consistently.packages/app/src/pages/layout.tsx (1)
651-664: 💤 Low valueOptional: Consider batching upsert state updates.
The multiple
setPawworkSessionWindowStatecalls could trigger separate re-renders. While the conditional guards limit this in practice, wrapping inbatch()would ensure a single update cycle when multiple properties change.♻️ Optional batch optimization
const upsertPawworkWindowSession = (info: Session) => { if (info.parentID || info.time?.archived) return + batch(() => { setPawworkSessionWindowState("normal", (current) => sortPawworkSessionWindowSessions([...current.filter((session) => session.id !== info.id), info]), ) if (store.pawworkPinnedSessions.includes(info.id)) { setPawworkSessionWindowState("pinned", (current) => sortPawworkSessionWindowSessions([...current.filter((session) => session.id !== info.id), info]), ) } if (params.id === info.id) { setPawworkSessionWindowState("active", info) } + }) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/app/src/pages/layout.tsx` around lines 651 - 664, The upsertPawworkWindowSession function calls setPawworkSessionWindowState up to three times which can cause multiple renders; wrap those state updates in a single batch() call (or the appropriate React/third-party batching util) so the updates to "normal", "pinned" and "active" are applied in one transaction—identify upsertPawworkWindowSession and replace the separate setPawworkSessionWindowState invocations with a single batch(() => { ... }) block that performs the same filtered/updated assignments for each state key, preserving the conditional checks for info.parentID, info.time?.archived, store.pawworkPinnedSessions.includes(info.id), and params.id === info.id.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/app/src/pages/layout/pawwork-session-window.ts`:
- Around line 43-46: The current logic computes `normal` by sorting and slicing
before removing `input.pinned` and `input.active`, causing pinned/active items
that appear in `normal` to consume the capped slots; change the flow so you
first sort the full `input.normal` via `sortPawworkSessionWindowSessions`, then
remove any sessions whose id appears in `input.pinned` or `input.active` before
applying the `limit` (computed as `Math.min(PAWWORK_SESSION_WINDOW_MAX,
Math.max(PAWWORK_SESSION_WINDOW_INITIAL, input.limit))`), and finally pass the
trimmed, sliced `normal` into `mergeSessionsByID` along with `input.pinned` and
`input.active`; ensure you use `normal.map(item => item.id)` (i.e., `normalIDs`)
after exclusion and slicing so IDs reflect the final window.
---
Nitpick comments:
In `@packages/app/src/pages/layout.tsx`:
- Around line 651-664: The upsertPawworkWindowSession function calls
setPawworkSessionWindowState up to three times which can cause multiple renders;
wrap those state updates in a single batch() call (or the appropriate
React/third-party batching util) so the updates to "normal", "pinned" and
"active" are applied in one transaction—identify upsertPawworkWindowSession and
replace the separate setPawworkSessionWindowState invocations with a single
batch(() => { ... }) block that performs the same filtered/updated assignments
for each state key, preserving the conditional checks for info.parentID,
info.time?.archived, store.pawworkPinnedSessions.includes(info.id), and
params.id === info.id.
In `@packages/opencode/test/session/session.test.ts`:
- Around line 268-293: Replace the plain Jest test with the project’s
Effect-aware pattern: import testEffect from "test/lib/effect.ts" and define
const it = testEffect(...) at the top of the file, then change test("backfill
preserves legacy session updated time", ...) to it.live("backfill preserves
legacy session updated time", async () => { ... }); inside the test body stop
calling Effect.runPromise(SessionNs.backfillExecutionContext) directly and
instead run the backfill as part of the effect test runtime (i.e., invoke
SessionNs.backfillExecutionContext through the it.live/Effect runtime), keeping
the rest of the logic (SessionNs.create, Database.use updates, assertions on
time_updated, and SessionNs.remove) intact so the test uses the live
git/filesystem/database fixtures consistently.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: fd30c43f-729b-4ec7-a488-835c8a024802
📒 Files selected for processing (12)
packages/app/src/context/global-sync/event-reducer.test.tspackages/app/src/context/global-sync/event-reducer.tspackages/app/src/i18n/en.tspackages/app/src/i18n/zh.tspackages/app/src/pages/layout.tsxpackages/app/src/pages/layout/pawwork-session-window.test.tspackages/app/src/pages/layout/pawwork-session-window.tspackages/app/src/pages/layout/pawwork-sidebar.tsxpackages/opencode/src/server/instance/experimental.tspackages/opencode/src/session/execution-context-store.tspackages/opencode/test/server/global-session-list.test.tspackages/opencode/test/session/session.test.ts
Summary
time_updatedduring execution context backfill.Why
Issue #382 is a bad data-loss-looking UI bug: older root sessions disappear from the sidebar, and creating/updating sessions could collapse already loaded history. The fix keeps the sidebar small by default while making older history reachable without per-project overfetching.
Related Issue
Closes #382
Human Review Status
Pending. A human should make the final merge decision after reviewing the final diff and verification evidence.
Review Focus
session.created/session.updatedno longer trim expanded sidebar history.X-Next-Cursoris limited to the experimental route and only when a next page exists.Risk Notes
How To Verify
Screenshots or Recordings
Not attached because the Electron verification used a copied installed-app database containing private local session titles. Manual Computer Use verification covered the visible UI flow: 30 sessions, Show more, 60 sessions, Show more, 90-session cap, and Search entry.
Checklist
dev, and my PR title and commit messages use Conventional Commits in EnglishSummary by CodeRabbit
New Features
Bug Fixes
Localization