fix(export): paginate the archive size estimate and explain scope counts (#1635)

The period branch of estimateArchiveSize ran a single unpaginated
document read with one flat IN() over every posted entry id in the
year: past the PostgREST row cap it silently undercounts, and past a
few hundred entry ids the URL itself blows up. Chunk the id filter
(CHILD_FK_CHUNK) and paginate every read with fetchAllRows, mirroring
what writeDocuments already did (the ZIP content was never affected).

The dialog now says per scope which documents are counted: full
history includes unlinked inbox/receipt documents, a single year only
those linked to posted vouchers. Without that line, a company with
many unlinked receipts reads the count gap as a pagination bug.

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-08-17 10:20:18 +02:00
committed by GitHub
parent 62c6fc44fe
commit 2eb3441244
6 changed files with 83 additions and 20 deletions
+18 -9
View File
@@ -175,15 +175,24 @@ export function FullArchiveDialog({
</DialogDescription>
</DialogHeader>
<div className="space-y-4">
<SegmentedControl
value={scope}
onChange={setScope}
aria-label={t('archive_scope_label')}
options={[
{ value: 'all', label: t('archive_scope_all') },
{ value: 'period', label: t('archive_scope_period') },
]}
/>
<div className="space-y-2">
<SegmentedControl
value={scope}
onChange={setScope}
aria-label={t('archive_scope_label')}
options={[
{ value: 'all', label: t('archive_scope_all') },
{ value: 'period', label: t('archive_scope_period') },
]}
/>
{/* The two scopes count different document sets (all documents vs
only those linked to posted vouchers in the year), so a company
with unlinked inbox receipts sees very different counts. Say so,
or the gap reads as a pagination bug. */}
<p className="text-xs leading-5 text-muted-foreground">
{scope === 'all' ? t('archive_scope_all_note') : t('archive_scope_period_note')}
</p>
</div>
{scope === 'period' && (
<FiscalYearSelector