mirror of
https://github.com/actualbudget/actual.git
synced 2026-04-30 09:50:18 -05:00
Fix duplicate transaction updates in Find & Replace
- Add deduplication logic to prevent duplicate updates when multiple members of a split transaction are selected - Add comprehensive tests for applyFindReplace function - Fixes issue where selecting parent and children of split transactions caused duplicates Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>
This commit is contained in:
@@ -175,7 +175,21 @@ export function useTransactionBatchActions() {
|
||||
: diff.added;
|
||||
});
|
||||
|
||||
await send('transactions-batch-update', changes);
|
||||
// Deduplicate changes by ID to prevent duplicate updates when
|
||||
// multiple members of a split transaction are selected
|
||||
const deduplicatedChanges: Diff<TransactionEntity> = {
|
||||
added: Array.from(
|
||||
new Map(changes.added?.map(item => [item.id, item])).values(),
|
||||
),
|
||||
updated: Array.from(
|
||||
new Map(changes.updated?.map(item => [item.id, item])).values(),
|
||||
),
|
||||
deleted: Array.from(
|
||||
new Map(changes.deleted?.map(item => [item.id, item])).values(),
|
||||
),
|
||||
};
|
||||
|
||||
await send('transactions-batch-update', deduplicatedChanges);
|
||||
|
||||
onSuccess?.(ids, name, value, mode);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
applyFindReplace,
|
||||
currencyToAmount,
|
||||
getNumberFormat,
|
||||
looselyParseAmount,
|
||||
@@ -229,3 +230,38 @@ describe('utility functions', () => {
|
||||
expect(stringToInteger('−3')).toBe(-3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('applyFindReplace', () => {
|
||||
test('basic string replacement works', () => {
|
||||
expect(applyFindReplace('hello world', 'world', 'universe', false)).toBe(
|
||||
'hello universe',
|
||||
);
|
||||
expect(applyFindReplace('test test test', 'test', 'demo', false)).toBe(
|
||||
'demo demo demo',
|
||||
);
|
||||
});
|
||||
|
||||
test('handles null and empty values', () => {
|
||||
expect(applyFindReplace(null, 'test', 'replace', false)).toBe('');
|
||||
expect(applyFindReplace(undefined, 'test', 'replace', false)).toBe('');
|
||||
expect(applyFindReplace('', 'test', 'replace', false)).toBe('');
|
||||
expect(applyFindReplace('hello', '', 'replace', false)).toBe('hello');
|
||||
});
|
||||
|
||||
test('regex replacement works', () => {
|
||||
expect(applyFindReplace('test123', '\\d+', 'NUM', true)).toBe('testNUM');
|
||||
expect(applyFindReplace('foo bar baz', 'b\\w+', 'word', true)).toBe(
|
||||
'foo word word',
|
||||
);
|
||||
});
|
||||
|
||||
test('handles invalid regex gracefully', () => {
|
||||
expect(applyFindReplace('test', '[invalid', 'replace', true)).toBe('test');
|
||||
});
|
||||
|
||||
test('case-sensitive replacement', () => {
|
||||
expect(applyFindReplace('Test test TEST', 'test', 'demo', false)).toBe(
|
||||
'Test demo TEST',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user