Skip to content

fix: session logs loading state#3712

Merged
joeyorlando merged 2 commits intomainfrom
codex/llm-session-logs-loading
Apr 11, 2026
Merged

fix: session logs loading state#3712
joeyorlando merged 2 commits intomainfrom
codex/llm-session-logs-loading

Conversation

@joeyorlando
Copy link
Copy Markdown
Contributor

@joeyorlando joeyorlando commented Apr 10, 2026

What changed

  • Added an explicit loading row to /llm/logs/session/[sessionId] while the session interactions query is pending.
  • Added a focused frontend test covering both pending and completed-empty interaction states.

Why

Long-running session log requests previously defaulted the pending query result to an empty array, so the page could briefly show "No interactions found for this session" before logs finished loading.

@joeyorlando joeyorlando changed the title [codex] fix session log loading state fix: session log loading state Apr 10, 2026
@joeyorlando joeyorlando marked this pull request as ready for review April 10, 2026 18:36
@claude
Copy link
Copy Markdown
Contributor

claude bot commented Apr 10, 2026

Claude finished @joeyorlando's task in 4m 41s —— View job


PR Review: fix: session log loading state

  • Read CLAUDE.md for repo guidelines
  • Read changed files
  • Verify useInteractions hook contract (isLoading exists, data?.data ?? [] flow)
  • Check sibling logs pages for loading patterns
  • Post review feedback

Summary

Small, targeted fix that correctly addresses the "No interactions found for this session" flash on /llm/logs/session/[sessionId]. The change reads isLoading from useInteractions and renders an explicit loading row before the empty‑state branch. The new test covers the two key states (loading vs. empty‑after‑load). Follows the repo guideline of preferring useQuery with explicit loading states (CLAUDE.md, "Frontend" section).

The change is minimal, scoped, and aligned with the rest of the codebase. I'd ship this. A few small observations below.


Observations

1. isLoading vs. isFetching on pagination — minor

useQuery's isLoading is isPending && isFetching, i.e. true only when there is no cached data yet. That's exactly the behavior you want for the first navigation to a session — fixes the flash. However, when the user clicks Next/Previous on the pagination control, the previous page's data stays in the cache for that query key, and the new offset triggers a fresh request where isLoading is false and isFetching is true. The old page rows will remain visible until the new ones land (TanStack default behavior, no keepPreviousData/placeholderData), with no in-table indicator that the next page is loading.

That is arguably an improvement over a flash, but if the goal is "show a loading row whenever the table is fetching session logs", consider isFetching instead of (or in addition to) isLoading. As written, the fix is correct for the bug described in the PR body — just flagging the pagination case as a follow-up consideration.

2. Sibling page uses a different loading affordance

platform/frontend/src/app/llm/logs/[id]/page.client.tsx:63-64 renders <LoadingSpinner /> (from @/components/loading) for its pending state. This PR introduces an inline table row with a Loader2 spinner from lucide. Both are valid; the inline row is actually nicer here because it preserves the page header, summary card, and table chrome while loading. Just noting the inconsistency in case there's a desire to standardize via LoadingSpinner/a shared <TableLoadingRow> later.

3. Hard-coded colSpan={6}

page.client.tsx:278 and page.client.tsx:290 both use colSpan={6}, matching the six <TableHead> columns above. Pre-existing pattern (the empty-state row already does this), so not a blocker — but it's the kind of thing that silently breaks when columns change. A const COLUMN_COUNT = 6; near the top, or counting TableHead children, would be nice if you ever touch this file again.

4. vi.mock("react", …) is heavy-handed

page.client.test.tsx:20-26 mocks the entire react module to stub use() so useSessionId resolves synchronously. This works, but it's the only place in the frontend tests doing this (per grep -l 'vi.mock("react"' frontend/src). Two lighter alternatives:

  • Use the Suspense wrapper that production uses: render via <Suspense fallback={null}> and await screen.findByText(...)React.use() will unwrap the resolved promise on the next tick. The test already uses findBy*, so it would just work.
  • Don't mock react at all and instead rely on await Promise.resolve() flushing — paramsPromise is already a resolved promise, and React.use supports thenables.

Mocking core React is the kind of thing that can interact badly with future React/Testing Library upgrades (e.g., concurrent rendering helpers). Worth avoiding if a Suspense wrapper works.

Fix this →

5. Type coverage of mocked hook return values

The as unknown as ReturnType<typeof useInteractions> casts (test lines 32, 37, 45, 69) silently allow shape drift between the real hook and the mock. Not a blocker for a focused state test, but a small function mockUseInteractions(overrides: Partial<ReturnType<typeof useInteractions>>): ReturnType<typeof useInteractions> helper would catch future breakage if the hook starts returning additional fields the component depends on.

6. Test naming nit

"shows the empty state after session interactions finish loading empty" reads slightly awkwardly. Consider "shows the empty state when the session has no interactions".


Verdict

LGTM — a clean bug fix with a focused test. The notes above are all non-blocking polish/follow-ups. The pagination behavior (point 1) is the only one I'd actually consider tightening before merge, depending on how often users page through a session's logs in practice.
Branch

@joeyorlando joeyorlando changed the title fix: session log loading state fix: session logs loading state Apr 11, 2026
@joeyorlando joeyorlando merged commit ffba126 into main Apr 11, 2026
40 checks passed
@joeyorlando joeyorlando deleted the codex/llm-session-logs-loading branch April 11, 2026 02:06
joeyorlando added a commit that referenced this pull request Apr 11, 2026
🤖 I have created a release *beep* *boop*
---


##
[1.2.10](platform-v1.2.9...platform-v1.2.10)
(2026-04-11)


### Features

* make posthog analytics configurable
([#3707](#3707))
([7ae9101](7ae9101))


### Bug Fixes

* `/llm/costs` table scrolling
([#3722](#3722))
([6a42ba8](6a42ba8))
* apply MCP OAuth lifetime for gateway slugs
([#3711](#3711))
([362aaec](362aaec))
* Bedrock tool name encoding
([#3706](#3706))
([0e2c2d1](0e2c2d1))
* costs timeframes and surface limit reset settings
([#3709](#3709))
([6e4154b](6e4154b))
* jira oauth discovery overrides
([#3721](#3721))
([2c4cf8f](2c4cf8f))
* OIDC discovery trusted origins for IdP registration
([#3714](#3714))
([adb5f5e](adb5f5e))
* preserve shared chat agents on fork
([#3715](#3715))
([252edfc](252edfc))
* reranker model dropdown labels
([#3704](#3704))
([ebd1c8a](ebd1c8a))
* session logs loading state
([#3712](#3712))
([ffba126](ffba126))


### Miscellaneous Chores

* **ci:** add ID-JAG MCP e2e test
([#3702](#3702))
([1a5078a](1a5078a))
* **deps:** bump next from 16.1.7 to 16.2.3 in /platform/frontend
([#3708](#3708))
([d47967c](d47967c))
* use neutral token prefixes with legacy support
([#3719](#3719))
([db5929c](db5929c))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: archestra-ci[bot] <222894074+archestra-ci[bot]@users.noreply.github.com>
Co-authored-by: Joey Orlando <joey@archestra.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant