Skip to content

fix: keep the "Load more" spinner up until the page query returns - #3976

Closed
chasers wants to merge 1 commit into
mainfrom
fix/load-more-spinner
Closed

chasers wants to merge 1 commit into
mainfrom
fix/load-more-spinner

Conversation

@chasers

@chasers chasers commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Stack 1/7 — "Load more" pagination fixes.

  • Problem: the spinner stops in milliseconds. The page query still runs for seconds.
  • Cause: phx-click-loading covers only the event round trip. The query runs async.
  • Fix: EventPagination gets a :loading button state.
  • load_events sets it. The page result and the page error clear it.
  • The button stays disabled while it loads. A second click does nothing.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YBPF1knvgfghTSdxuYryGL

@chasers

chasers commented Sep 14, 2026

Copy link
Copy Markdown
Contributor Author

Third commit: scroll to the bottom when a search runs.

A chart click already scrolled to the newest results via scroll_to_bottom_on_result?, but running a search did not, so submitting a query left the viewport wherever it was. start_search now sets the same flag.

The search button and the Enter key both route through a single event — lql_editor_wrapper_hook.js binds monaco.KeyCode.Enter (line 90) and the submit listener (line 55) to the same submitSearch/0, which pushes start_search — so one change covers both.

Verified: mix test test/logflare_web/live/search_live/ 119/0, MIX_ENV=test mix ci exit 0.

@chasers

chasers commented Sep 14, 2026

Copy link
Copy Markdown
Contributor Author

Fifth commit — and this one is almost certainly the staging bug.

The scan had no far side

A page request drops the query's timestamp range so it can page past it, and kept only a one-sided partition bound:

WHERE EXTRACT(DATE FROM t0.timestamp) <= '2026-09-14'
  AND (t0.timestamp < TIMESTAMP_MICROS(?) OR ...)

Nothing bounds the other end, so on BigQuery that reads every partition the source has ever had. On a small table it returns; on a production table it does not.

A page now moves by the window you are looking at

The scan is [cursor - window, cursor] going back and [cursor, cursor + window] going forward, where window is the width of the range currently in view (floor: 60 seconds). The query carries a TIMESTAMP_MICROS bound and a partition-date bound on both sides, for :timestamp, :pseudo and Postgres alike.

Two consequences, both wanted:

  • The LQL range grows by that same window on every click, instead of only when the returned rows happened to fall outside it. That is why the range looked frozen even when rows loaded.
  • An empty window no longer stalls the button. The cursor shifts by the window rather than clearing, so the next click keeps walking back. extend_timestamp_range/2 is gone.

The buttons say what they do

Load more (-10 minutes) on top, Load more (+10 minutes) on the bottom, humanized from the same window the query uses — seconds, minutes, hours or days, singular or plural.

Verification

mix test test/logflare/logs/ test/logflare_web/live/search_live/ — 263 tests, 0 failures, including new SQL-level tests asserting both bounds and the window arithmetic. MIX_ENV=test mix ci — exit 0.

@chasers
chasers force-pushed the fix/load-more-spinner branch from 4fa544b to 26ae0c0 Compare September 14, 2026 18:44
@chasers
chasers added this pull request to stack #3983 September 14, 2026 18:44
The button drove its spinner from `phx-click-loading`, which LiveView applies
only while the event round trip is in flight. `load_events` hands the query to
`SearchQueryExecutor` and returns immediately, so the spinner stopped in
milliseconds while a BigQuery page query still took seconds.

`EventPagination` now carries a `loading_intent` and a fourth button state,
`:loading`. `load_events` marks the intent, and the page result and page error
handlers clear it. The button renders its spinner from that state. A hidden
button stays hidden, and `disabled={@State != :ready}` already covers
`:loading`, so a second click cannot queue behind the first.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YBPF1knvgfghTSdxuYryGL
@chasers
chasers force-pushed the fix/load-more-spinner branch from 26ae0c0 to 9332ab7 Compare September 17, 2026 19:30
@chasers
chasers removed this pull request from stack #3983 September 17, 2026 21:09
chasers added a commit that referenced this pull request Sep 17, 2026
Squashes the nine-PR load more stack into one commit: #3976, #3977, #3978,
#3979, #3980, #3981, #3982, #3984 and #3986. Merged as a unit so that main
never carries the intermediate states that #3984 corrects.

Pagination

- Keep the "Load more" spinner up until the page query returns.
- Bound a page request to the window in view and say so on the button.
- Store one page window per search in `EventPagination`. The label, the
  query, the cursor shift and the range growth all read it. The window no
  longer doubles on each click.
- Set the page window from a tail result too. A soft pause, play and pause
  used to leave the window nil and drop the next page request.
- Write an implied timestamp range into the query on a page request.
- Keep a one-sided `t:` bound when a page request makes the range explicit.
- Clamp a "next" range extension at now. Each empty click used to push the
  range max another window into the future.
- Cap the cursor of an empty "next" page at the request time.
- Remove timestamp clauses that can never match.
- Stop hiding the load more buttons on a short page.
- Disable the other button while a page request runs.
- Drop a page result or page error that no request waits for.
- Clear the page spinner when a search fails to parse.
- Log a page request that the LiveView drops.

Scrolling

- The LiveView drives every scroll. Every initial event page and every tail
  append pushes `scroll-to-bottom`. The server owns scroll intent. The hook
  owns viewport stability.

Cleanup

- Remove the unused sentinel row: the extra fetched row, `fetch_limit/0`
  and the `has_more?` field that nothing reads.
- Build the chart range in the search timezone. An implied range is no
  longer UTC written as local time.
- Remove the 750ms LiveView latency simulator in dev.

Tests

- Cover event pagination against a bigquery source and a postgres source.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@chasers

chasers commented Sep 17, 2026

Copy link
Copy Markdown
Contributor Author

Merged as part of the squashed stack in #3986, which landed on main as 9c9913b. The whole stack merged as one unit so that main never carried the intermediate states that #3984 corrects. This PR's commits are all included there.

@chasers chasers closed this Sep 17, 2026
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.

2 participants