Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rules with splits #2059

Merged
merged 33 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9186018
Add split creation UI to rule creation modal
jfdoming Nov 25, 2023
75b08d7
Support applying splits when rules execute
jfdoming Dec 9, 2023
4d0b27e
fix: deserialize transaction before running rules
jfdoming Dec 23, 2023
2b8a74b
Add release notes
jfdoming Dec 23, 2023
2991bfa
Fix missing types pulled in from master
jfdoming Dec 23, 2023
7dec727
PR feedback: use `getActions`
jfdoming Dec 26, 2023
fa4d410
PR feedback: use `flatMap`
jfdoming Dec 26, 2023
9fc68e6
Fix action deletion
jfdoming Dec 27, 2023
36a6a31
Don't flicker upon split deletion
jfdoming Dec 28, 2023
90ca118
Let users specify parent transaction actions (e.g. linking schedules)
jfdoming Dec 28, 2023
7d5c4c1
Support empty splits
jfdoming Dec 28, 2023
a91280c
Revert adding `no-op` action type
jfdoming Jan 6, 2024
a0a9455
Support splits by percent
jfdoming Jan 14, 2024
cecc709
Fix types
jfdoming Jan 14, 2024
7e2d88d
Fix crash on transactions page when posting a transaction
jfdoming Jan 15, 2024
51b9917
Fix a bug where schedules wouldn't be marked as completed
jfdoming Jan 15, 2024
99e99df
Add feature flag
jfdoming Jan 23, 2024
da020ef
Limit set actions within splits to fewer fields
jfdoming Jan 23, 2024
d4d013f
Fix merge conflict
jfdoming Jan 23, 2024
6af84fb
Don't run split rules if feature is disabled
jfdoming Jan 23, 2024
1e1777a
Fix percent-based splits not applying
jfdoming Jan 27, 2024
0d89f75
Fix crash when editing parent transaction amount
jfdoming Jan 28, 2024
ecf560a
Merge branch 'master' into jfdoming/add-splits-to-rules
jfdoming Jan 28, 2024
7ea00e9
Auto-format
jfdoming Jan 28, 2024
a9b29e7
Attempt to fix failing tests
jfdoming Feb 3, 2024
d2e9796
More test/bug fixes
jfdoming Feb 3, 2024
5b4536c
Merge branch 'master' into jfdoming/add-splits-to-rules
jfdoming Feb 3, 2024
58cfe50
Add an extra split at the end if there is a remaining amount
jfdoming Feb 3, 2024
e855272
Make sure split has correct values for dynamic remainder
jfdoming Feb 3, 2024
573e831
Remove extraneous console.log
jfdoming Feb 3, 2024
42ff7fe
Merge branch 'master' into jfdoming/add-splits-to-rules
jfdoming Feb 3, 2024
54fd311
Merge branch 'master' into jfdoming/add-splits-to-rules
jfdoming Feb 3, 2024
814934a
Merge branch 'master' into jfdoming/add-splits-to-rules
jfdoming Feb 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
355 changes: 288 additions & 67 deletions packages/desktop-client/src/components/modals/EditRule.jsx

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export function ExperimentalFeatures() {
Goal templates
</FeatureToggle>
<FeatureToggle flag="simpleFinSync">SimpleFIN sync</FeatureToggle>
<FeatureToggle flag="splitsInRules">Splits in rules</FeatureToggle>
</View>
) : (
<LinkButton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import { type CSSProperties, styles } from '../../style';
import { Text } from '../common/Text';
import { ConditionalPrivacyFilter } from '../PrivacyFilter';

import { useFormat } from './useFormat';
import { type FormatType, useFormat } from './useFormat';
import { useSheetName } from './useSheetName';
import { useSheetValue } from './useSheetValue';

import { type Binding } from '.';

type CellValueProps = {
binding: string | Binding;
type?: string;
type?: FormatType;
formatter?: (value) => ReactNode;
style?: CSSProperties;
getStyle?: (value) => CSSProperties;
Expand Down
10 changes: 8 additions & 2 deletions packages/desktop-client/src/components/spreadsheet/useFormat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@ import { useSelector } from 'react-redux';
import { selectNumberFormat } from 'loot-core/src/client/selectors';
import { integerToCurrency } from 'loot-core/src/shared/util';

export type FormatType =
| 'string'
| 'number'
| 'financial'
| 'financial-with-sign';

function format(
value: unknown,
type = 'string',
type: FormatType = 'string',
formatter?: Intl.NumberFormat,
): string {
switch (type) {
Expand Down Expand Up @@ -49,7 +55,7 @@ export function useFormat() {
const numberFormat = useSelector(selectNumberFormat);

return useCallback(
(value: unknown, type = 'string') =>
(value: unknown, type: FormatType = 'string') =>
format(value, type, numberFormat.formatter),
[numberFormat],
);
Expand Down
4 changes: 2 additions & 2 deletions packages/desktop-client/src/components/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import {
mergeConditionalPrivacyFilterProps,
} from './PrivacyFilter';
import { type Binding } from './spreadsheet';
import { useFormat } from './spreadsheet/useFormat';
import { type FormatType, useFormat } from './spreadsheet/useFormat';
import { useSheetValue } from './spreadsheet/useSheetValue';
import { Tooltip, IntersectionBoundary } from './tooltips';

Expand Down Expand Up @@ -660,7 +660,7 @@ export function SelectCell({

type SheetCellValueProps = {
binding: Binding;
type: string;
type: FormatType;
getValueStyle?: (value: string | number) => CSSProperties;
formatExpr?: (value) => string;
unformatExpr?: (value: string) => unknown;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -992,27 +992,31 @@ function TransactionEditUnconnected(props) {
return null;
}

const onEdit = async transaction => {
let newTransaction = transaction;
const onEdit = async serializedTransaction => {
const transaction = deserializeTransaction(
serializedTransaction,
null,
dateFormat,
);

// Run the rules to auto-fill in any data. Right now we only do
// this on new transactions because that's how desktop works.
if (isTemporary(transaction)) {
const afterRules = await send('rules-run', { transaction });
const diff = getChangedValues(transaction, afterRules);

newTransaction = { ...transaction };
if (diff) {
Object.keys(diff).forEach(field => {
if (newTransaction[field] == null) {
newTransaction[field] = diff[field];
if (transaction[field] == null) {
transaction[field] = diff[field];
}
});
}
}

const { data: newTransactions } = updateTransaction(
transactions,
deserializeTransaction(newTransaction, null, dateFormat),
transaction,
);
setTransactions(newTransactions);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ import {
updateTransaction,
deleteTransaction,
addSplitTransaction,
groupTransaction,
ungroupTransactions,
} from 'loot-core/src/shared/transactions';
import {
integerToCurrency,
Expand Down Expand Up @@ -689,6 +691,7 @@ function PayeeIcons({
const Transaction = memo(function Transaction(props) {
const {
transaction: originalTransaction,
subtransactions,
editing,
showAccount,
showBalance,
Expand Down Expand Up @@ -827,7 +830,8 @@ const Transaction = memo(function Transaction(props) {
// Run the transaction through the formatting so that we know
// it's always showing the formatted result
setTransaction(serializeTransaction(deserialized, showZeroInDeposit));
onSave(deserialized);

onSave(deserialized, subtransactions);
}
}

Expand Down Expand Up @@ -1473,9 +1477,10 @@ function NewTransaction({
const error = transactions[0].error;
const isDeposit = transactions[0].amount > 0;

const emptyChildTransactions = transactions.filter(
t => t.parent_id === transactions[0].id && t.amount === 0,
const childTransactions = transactions.filter(
t => t.parent_id === transactions[0].id,
);
const emptyChildTransactions = childTransactions.filter(t => t.amount === 0);

return (
<View
Expand All @@ -1497,6 +1502,7 @@ function NewTransaction({
key={transaction.id}
editing={editingTransaction === transaction.id}
transaction={transaction}
subtransactions={transaction.is_parent ? childTransactions : null}
showAccount={showAccount}
showCategory={showCategory}
showBalance={showBalance}
Expand Down Expand Up @@ -2048,18 +2054,28 @@ export const TransactionTable = forwardRef((props, ref) => {
}, [props.onAdd, newNavigator.onEdit]);

const onSave = useCallback(
async transaction => {
async (transaction, subtransactions = null) => {
savePending.current = true;

let groupedTransaction = subtransactions
? groupTransaction([transaction, ...subtransactions])
: transaction;

if (isTemporaryId(transaction.id)) {
if (props.onApplyRules) {
transaction = await props.onApplyRules(transaction);
groupedTransaction = await props.onApplyRules(groupedTransaction);
}

const newTrans = latestState.current.newTransactions;
setNewTransactions(updateTransaction(newTrans, transaction).data);
// Future refactor: we shouldn't need to iterate through the entire
// transaction list to ungroup, just the new transactions.
setNewTransactions(
ungroupTransactions(
updateTransaction(newTrans, groupedTransaction).data,
),
);
} else {
props.onSave(transaction);
props.onSave(groupedTransaction);
}
},
[props.onSave],
Expand Down
1 change: 1 addition & 0 deletions packages/desktop-client/src/hooks/useFeatureFlag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const DEFAULT_FEATURE_FLAG_STATE: Record<FeatureFlag, boolean> = {
goalTemplatesEnabled: false,
customReports: false,
simpleFinSync: false,
splitsInRules: false,
};

export function useFeatureFlag(name: FeatureFlag): boolean {
Expand Down
Loading
Loading