Skip to content

imp: web: page the journal and register views, and link to each year (#586) - #2749

Merged
simonmichael merged 3 commits into
hledgerorg:mainfrom
acinader:web-paging
Sep 30, 2026
Merged

simonmichael merged 3 commits into
hledgerorg:mainfrom
acinader:web-paging

Conversation

@acinader

@acinader acinader commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

hledger-web's journal and register views render every matching transaction into one page. A journal of 16,000 transactions gives a 19 MB journal page with 48,000 table rows and a 22 MB register page: slow to transfer and render. Fixes #586.

This PR pages the two views, in the simple server-rendered way suggested in #848:

journal-paged
  • The journal and register views show the newest 1000 matching transactions, with a line saying which ("Showing 1 to 1,000 of 16,063 transactions"), links to the newer and older pages, and the pages by number, up to ten at a time around the current one. A page parameter in the URL names the page, so pages can be bookmarked; a missing or bad one means the first page, one past the end means the last.
  • The report is computed in full and then sliced, so the register's running balance column continues across pages, and the register chart plots the rows on the page.
  • When the matching transactions span more than one year, a row of years above the table links to the search narrowed to each year (date:2025 replacing any date term), with All to widen it again. More than twenty years are grouped by decade.
  • A link from one view to a transaction in the other (a register row's date, a posting's account) names the transaction, so the view opens on the page holding it and scrolls to it as before.
  • Journals with under 1000 transactions in one year see no change. A multi-year journal of any size gets the years row, since it is navigation rather than a size measure.
  • Pages are newest first, so a bookmarked page=3 drifts as transactions are added; the year links are the stable bookmarks.
  • The page size is one named constant in Hledger.Web.Paging; it keeps a page to a megabyte or two and a few thousand rows.

Also: tools/generatejournal gains --start and --days, and just samplejournals makes two journals for trying this: a sparse century (1000 transactions over a hundred years, which fits on one page and shows the decade rows) and a dense year (6000 transactions, six pages).

Tests: yesod-test cases for slicing, the links at both ends, clamping, bad page numbers, the page-size boundary, the page-number window, the years row (with negated terms and under --depth), carrying the rest of the search, the register balance and chart across a page boundary, linked transactions, decade grouping, and small journals' unchanged pages; a browser spec for what only a browser shows: a paged page loading without policy violations, the register chart drawn from the page's rows, and a link to a transaction on another page scrolling to it. The JSON API is unchanged.

How to test

stack build hledger-web
tools/generatejournal 6000 100 4 --start=2026-01-01 --days=365 > examples/dense-year.journal
stack exec -- hledger-web -f examples/dense-year.journal --serve --port 5062

http://127.0.0.1:5062/journal shows "Showing 1 to 1,000 of 6,000 transactions 1 2 3 4 5 6 Older ›", with 1 in bold and not a link; http://127.0.0.1:5062/journal?page=6 is the last page, with "‹ Newer" and 6 in bold. With a multi-year journal the years row appears above the table.

AI usage: Claude Fable 5.1, plus Claude Opus 5.5 for preparing this PR. About 0.38M output tokens in the main sessions (the per-commit estimates in the commit messages sum to ~76k; the rest went to planning, review triage, the test plan, and drafting), plus the subagent runs below, which produced findings, not code. Output is what the model wrote; total adds the input it read, mostly cached context re-read on each turn.

Run Output Total
Main session: plan, code, tests, and docs (Fable 5.1) 365k 67.5M
This PR's preparation (Opus 5.5) 16k 2.5M
Research for the plan, three subagents 1k 3.4M
Review, round 1 (23 findings) 129k 29.2M
Review, round 2 (13 findings) 47k 14.8M
Review, round 3, after the page numbers (nits only) 22k 7.6M
In all 580k 125.0M

…ledgerorg#586]

The journal and register views show the newest 1000 matching
transactions, a "Showing 1 to 1,000 of N transactions" line, Newer and
Older links, and up to ten numbered page links. A page parameter
selects the page; a missing or bad one means the first, one past the
end means the last. The report is sliced after it is computed, so the
register's running balance continues across pages; the register chart
plots the page's rows.

When the matches span more than one year, a years row links to the
search with date:YYYY in place of its date terms, plus All; more than
twenty years are grouped by decade.

Account links from a transaction, in the journal and the register,
carry a txn parameter, which opens the account's register on the page
holding it. (The register's date links open that day's journal entries.)

Tests: yesod-test cases for paging, the years row, and txn links; a
browser spec for policy violations, the register chart, and scrolling
to a linked transaction.

AI usage: Claude Fable 5.1, ~70k output tokens.
AI usage: Claude Fable 5.1, ~2k output tokens.
…rnals

--start sets the first day instead of 2000-01-01, and --days spreads
the transactions evenly over that many days instead of one per day.
Two new sample journals use them: century-sparse (1000 transactions
over a hundred years) and dense-year (6000 in one year), for trying
hledger-web's paging and years row.

AI usage: Claude Fable 5.1, ~4k output tokens.
@simonmichael
simonmichael merged commit ae9164a into hledgerorg:main Sep 30, 2026
2 checks passed
@simonmichael

Copy link
Copy Markdown
Member

I'm not seeing any paging UI with main. Is it just me ?

@acinader
acinader deleted the web-paging branch September 30, 2026 13:38
@acinader

Copy link
Copy Markdown
Contributor Author

I set the paging threshold really high at 1,000 transactions. If the journal or register has less than 1k, there is no difference. I chose that becauase at 1k or under the page is performant. It didn't start cuasing problems for me till about 3k.

image

@acinader

Copy link
Copy Markdown
Contributor Author

fyi, my household journal is 3.7M and 86k lines -- mostly comments and meta data.

image

@acinader

Copy link
Copy Markdown
Contributor Author

worth noting that I have not had it as a single file untl a few days ago when I started working on the bs, bse, cf, is stuff where I switched to a single file. I should now be a good performance test and I'll check that out and/or open an issue if i see performance issues.

@simonmichael

Copy link
Copy Markdown
Member

Ah, cool, I see it now. I had tested with just under 1000 txns.

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.

hledger-web sends the whole journal to the browser, every time

2 participants