Let reviews see low-confidence suggestions and rebase preview applies

A low-confidence answer was discarded inside Classify, so Analyse showed
the row as unchanged instead of a reviewable suggestion; the fallback
decision moves to the import path, which keeps the merchant link and the
recorded confidence. ApplyPreview now rebases onto the current journal:
unrelated commits during a minutes-long paced run no longer invalidate
the review, only an edit to a selected transaction itself conflicts, and
applied changes are pruned so the rest stay appliable.
This commit is contained in:
Lars Nolden
2026-09-12 18:35:38 +02:00
parent 9092c5721d
commit 2373790be3
6 changed files with 160 additions and 28 deletions
+14 -10
View File
@@ -359,9 +359,10 @@ export function Classification({
</span>
</div>
{preview.revision !== state.revision && (
<div className="alert error">
Your journal changed since this preview. Cancel it and generate a
fresh preview before applying.
<div className="alert">
Your journal changed since this preview. Selected changes still
apply as long as their transactions were not edited in the
meantime.
</div>
)}
<section className="panel">
@@ -449,11 +450,7 @@ export function Classification({
</button>
<button
className="button primary"
disabled={
busy ||
!selected.length ||
preview.revision !== state.revision
}
disabled={busy || !selected.length}
onClick={() => setConfirm(true)}
>
<Check size={16} />
@@ -506,7 +503,7 @@ export function Classification({
</button>
<button
className="button primary"
disabled={busy || preview.revision !== state.revision}
disabled={busy}
onClick={async () => {
setBusy(true);
setError("");
@@ -520,7 +517,14 @@ export function Classification({
result,
`Applied ${selected.length} classifications`,
);
setPreview(null);
const remaining = preview.changes.filter(
(c) => !selected.includes(c.id),
);
setPreview(
remaining.length
? { ...preview, changes: remaining }
: null,
);
setSelected([]);
setConfirm(false);
} catch (err) {