Skip to content

[Due for payment 2026-07-14] Sorting an all-empty column (Posted/Approved/Withdrawal ID) reorders rows and flips between asc/desc #94893

Description

@MelvinBot

Problem

Sorting an Expenses table by a column where every row is empty (e.g. Posted / Approved / Withdrawal ID) changes the row order, and ascending vs descending produce different orders.

Expected: sorting an all-empty column is a no-op — row order stays the same and is identical for both ascending and descending.

Root cause

The transaction sort adds a secondary tie-breaker that re-sorts tied rows by created, then transactionIDhonoring the user's sortOrder:

App/src/libs/SearchUIUtils.ts

Lines 3975 to 3986 in 241d30f

if (primaryComparison !== 0) {
return primaryComparison;
}
// If we have a tie in the primary comparison, we add a tie breaker on date and/or transactionID as a last resort to make the sort deterministic
const createdComparison = compareValues(a.created, b.created, sortOrder, 'created', localeCompare);
if (createdComparison !== 0) {
return createdComparison;
}
return compareValues(a.transactionID, b.transactionID, sortOrder, 'transactionID', localeCompare);

compareValues returns 0 when both values are empty, so for an all-empty column every primary comparison ties → the whole order is decided by that tie-breaker. Because it honors sortOrder, ascending orders the rows by date-ascending and descending by date-descending — hence the table reorders and flips between directions.

Why the report view is unaffected: its sort has no tie-breaker — it returns the primary compareValues directly and lets the stable Array.sort keep ties in place:

return compareValues(
getTransactionSortValue(a, sortBy, report, policy, policyCategories),
getTransactionSortValue(b, sortBy, report, policy, policyCategories),
sortOrder,
sortBy,
localeCompare,
true,
);
});

Introduced by: commit fac3dcefab9 "add tie breaker" in PR Expensify/App#77800 (Reimbursable/Billable columns) — added so low-cardinality (boolean) columns get a deterministic within-group order:

fac3dce

Proposed fix (FE)

Drop the sortOrder-dependent tie-breaker and return the primary comparison — the stable sort preserves ties, so an all-empty column becomes a true no-op, identical for asc/desc, and consistent with the report view.


Filed from this RCA comment by mukhrr on PR Expensify/App#93146.

Issue OwnerCurrent Issue Owner: @mallenexpensify

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Awaiting PaymentAuto-added when associated PR is deployed to productionDailyKSv2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions