Skip to content

Commit

Permalink
Merge branch 'master' into pull_2815
Browse files Browse the repository at this point in the history
  • Loading branch information
psybers committed Aug 24, 2024
2 parents 336a233 + 1750cd9 commit f604be3
Show file tree
Hide file tree
Showing 25 changed files with 209 additions and 48 deletions.
10 changes: 7 additions & 3 deletions .github/workflows/electron-master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,17 @@ jobs:
sudo flatpak install org.electronjs.Electron2.BaseApp/x86_64/23.08 -y
- name: Set up environment
uses: ./.github/actions/setup
- name: Build Electron
- name: Build Electron for Mac
if: ${{ startsWith(matrix.os, 'macos') }}
run: ./bin/package-electron
env:
# CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
# CSC_LINK: ${{ secrets.CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
CSC_LINK: ${{ secrets.CSC_LINK }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
- name: Build Electron
if: ${{ ! startsWith(matrix.os, 'macos') }}
run: ./bin/package-electron
- name: Upload Build
uses: actions/upload-artifact@v4
with:
Expand Down
4 changes: 2 additions & 2 deletions packages/desktop-client/src/components/accounts/Account.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -1113,10 +1113,10 @@ class AccountInternal extends PureComponent {
);
};

onConditionsOpChange = (value, conditions) => {
onConditionsOpChange = value => {
this.setState({ filterConditionsOp: value });
this.setState({ filterId: { ...this.state.filterId, status: 'changed' } });
this.applyFilters([...conditions]);
this.applyFilters([...this.state.filterConditions]);
if (this.state.search !== '') {
this.onSearch(this.state.search);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ export function FilterExpression<T extends RuleConditionEntity>({
valueIsRaw={
op === 'contains' ||
op === 'matches' ||
op === 'doesNotContain'
op === 'doesNotContain' ||
op === 'hasTags'
}
/>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,10 @@ function ConfigureField({
subfield={subfield}
type={
type === 'id' &&
(op === 'contains' || op === 'matches' || op === 'doesNotContain')
(op === 'contains' ||
op === 'matches' ||
op === 'doesNotContain' ||
op === 'hasTags')
? 'string'
: type
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function FiltersStack({
onReloadSavedFilter: (savedFilter: SavedFilter, value?: string) => void;
filterId: SavedFilter;
savedFilters: TransactionFilterEntity[];
onConditionsOpChange: () => void;
onConditionsOpChange: (value: 'and' | 'or') => void;
}) {
return (
<View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export function updateFilterReducer(
action.op === 'matches' ||
action.op === 'is' ||
action.op === 'doesNotContain' ||
action.op === 'isNot')
action.op === 'isNot' ||
action.op === 'hasTags')
) {
// Clear out the value if switching between contains or
// is/oneof for the id or string type
Expand Down
14 changes: 9 additions & 5 deletions packages/desktop-client/src/components/modals/EditRule.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export function FieldSelect({ fields, style, value, onChange }) {
bare
options={fields}
value={value}
onChange={value => onChange('field', value)}
onChange={onChange}
buttonStyle={{ color: theme.pageTextPositive }}
/>
</View>
Expand All @@ -116,7 +116,7 @@ export function OpSelect({
// TODO: Add matches op support for payees, accounts, categories.
.filter(op =>
type === 'id'
? !['contains', 'matches', 'doesNotContain'].includes(op)
? !['contains', 'matches', 'doesNotContain', 'hasTags'].includes(op)
: true,
)
.map(op => [op, formatOp(op, type)]);
Expand Down Expand Up @@ -260,7 +260,11 @@ function ConditionEditor({

return (
<Editor style={editorStyle} error={error}>
<FieldSelect fields={conditionFields} value={field} onChange={onChange} />
<FieldSelect
fields={conditionFields}
value={field}
onChange={value => onChange('field', value)}
/>
<OpSelect ops={ops} value={op} type={type} onChange={onChange} />

<View style={{ flex: 1 }}>{valueEditor}</View>
Expand Down Expand Up @@ -373,7 +377,7 @@ function ActionEditor({ action, editorStyle, onChange, onDelete, onAdd }) {
<FieldSelect
fields={options?.splitIndex ? splitActionFields : actionFields}
value={field}
onChange={onChange}
onChange={value => onChange('field', value)}
/>

<View style={{ flex: 1 }}>
Expand Down Expand Up @@ -838,7 +842,7 @@ export function EditRule({ defaultRule, onSave: originalOnSave }) {
setStage(stage);
}

function onChangeConditionsOp(name, value) {
function onChangeConditionsOp(value) {
setConditionsOp(value);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export function CustomReport() {
!!conditions.find(
({ field, op }) =>
field === 'category' &&
['contains', 'doesNotContain', 'matches'].includes(op),
['contains', 'doesNotContain', 'matches', 'hasTags'].includes(op),
) || conditions.filter(({ field }) => field === 'category').length >= 2;

const setSelectedCategories = (newCategories: CategoryEntity[]) => {
Expand Down
14 changes: 9 additions & 5 deletions packages/desktop-client/src/components/sidebar/Accounts.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @ts-strict-ignore
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';

import * as queries from 'loot-core/src/client/queries';
Expand Down Expand Up @@ -31,6 +32,7 @@ export function Accounts({
onToggleClosedAccounts,
onReorder,
}: AccountsProps) {
const { t } = useTranslation();
const [isDragging, setIsDragging] = useState(false);
const failedAccounts = useFailedAccounts();
const updatedAccounts = useUpdatedAccounts();
Expand Down Expand Up @@ -62,15 +64,15 @@ export function Accounts({
return (
<View>
<Account
name="All accounts"
name={t('All accounts')}
to="/accounts"
query={queries.allAccountBalance()}
style={{ fontWeight, marginTop: 15 }}
/>

{budgetedAccounts.length > 0 && (
<Account
name="For budget"
name={t('For budget')}
to="/accounts/budgeted"
query={queries.budgetedAccountBalance()}
style={{
Expand Down Expand Up @@ -100,7 +102,7 @@ export function Accounts({

{offbudgetAccounts.length > 0 && (
<Account
name="Off budget"
name={t('Off budget')}
to="/accounts/offbudget"
query={queries.offbudgetAccountBalance()}
style={{
Expand Down Expand Up @@ -131,7 +133,9 @@ export function Accounts({
{closedAccounts.length > 0 && (
<SecondaryItem
style={{ marginTop: 15 }}
title={'Closed accounts' + (showClosedAccounts ? '' : '...')}
title={
showClosedAccounts ? t('Closed accounts') : t('Closed accounts...')
}
onClick={onToggleClosedAccounts}
bold
/>
Expand All @@ -157,7 +161,7 @@ export function Accounts({
}}
onClick={onAddAccount}
Icon={SvgAdd}
title="Add account"
title={t('Add account')}
/>
</View>
);
Expand Down
19 changes: 11 additions & 8 deletions packages/desktop-client/src/components/sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux';

import { Resizable } from 're-resizable';
Expand Down Expand Up @@ -38,6 +39,7 @@ import { Tools } from './Tools';
export function Sidebar() {
const hasWindowButtons = !Platform.isBrowser && Platform.OS === 'mac';

const { t } = useTranslation();
const dispatch = useDispatch();
const sidebar = useSidebar();
const accounts = useAccounts();
Expand Down Expand Up @@ -149,10 +151,10 @@ export function Sidebar() {
</View>

<View style={{ overflow: 'auto' }}>
<Item title="Budget" Icon={SvgWallet} to="/budget" />
<Item title="Reports" Icon={SvgReports} to="/reports" />
<Item title={t('Budget')} Icon={SvgWallet} to="/budget" />
<Item title={t('Reports')} Icon={SvgReports} to="/reports" />

<Item title="Schedules" Icon={SvgCalendar} to="/schedules" />
<Item title={t('Schedules')} Icon={SvgCalendar} to="/schedules" />

<Tools />

Expand All @@ -177,6 +179,7 @@ export function Sidebar() {
}

function EditableBudgetName() {
const { t } = useTranslation();
const dispatch = useDispatch();
const navigate = useNavigate();
const [budgetName, setBudgetNamePref] = useMetadataPref('budgetName');
Expand Down Expand Up @@ -205,10 +208,10 @@ function EditableBudgetName() {
}

const items = [
{ name: 'rename', text: 'Rename budget' },
{ name: 'settings', text: 'Settings' },
...(Platform.isBrowser ? [{ name: 'help', text: 'Help' }] : []),
{ name: 'close', text: 'Close file' },
{ name: 'rename', text: t('Rename budget') },
{ name: 'settings', text: t('Settings') },
...(Platform.isBrowser ? [{ name: 'help', text: t('Help') }] : []),
{ name: 'close', text: t('Close file') },
];

if (editing) {
Expand Down Expand Up @@ -250,7 +253,7 @@ function EditableBudgetName() {
onPress={() => setMenuOpen(true)}
>
<Text style={{ whiteSpace: 'nowrap', overflow: 'hidden' }}>
{budgetName || 'A budget has no name'}
{budgetName || t('A budget has no name')}
</Text>
<SvgExpandArrow width={7} height={7} style={{ marginLeft: 5 }} />
</Button>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { type ComponentPropsWithoutRef } from 'react';
import { useTranslation } from 'react-i18next';

import { SvgPin } from '../../icons/v1';
import { SvgArrowButtonLeft1 } from '../../icons/v2';
Expand All @@ -17,11 +18,12 @@ export function ToggleButton({
isFloating,
onFloat,
}: ToggleButtonProps) {
const { t } = useTranslation();
return (
<View className="float" style={{ ...style, flexShrink: 0 }}>
<Button
variant="bare"
aria-label={`${isFloating ? 'Pin' : 'Unpin'} sidebar`}
aria-label={isFloating ? t('Pin sidebar') : t('Unpin sidebar')}
onPress={onFloat}
style={{ color: theme.buttonMenuBorder }}
>
Expand Down
8 changes: 5 additions & 3 deletions packages/desktop-client/src/components/sidebar/Tools.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useState, useCallback, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';

import {
Expand All @@ -14,6 +15,7 @@ import { Item } from './Item';
import { SecondaryItem } from './SecondaryItem';

export function Tools() {
const { t } = useTranslation();
const [isOpen, setOpen] = useState(false);
const onToggle = useCallback(() => setOpen(open => !open), []);
const location = useLocation();
Expand All @@ -40,19 +42,19 @@ export function Tools() {
{isOpen && (
<>
<SecondaryItem
title="Payees"
title={t('Payees')}
Icon={SvgStoreFront}
to="/payees"
indent={15}
/>
<SecondaryItem
title="Rules"
title={t('Rules')}
Icon={SvgTuning}
to="/rules"
indent={15}
/>
<SecondaryItem
title="Settings"
title={t('Settings')}
Icon={SvgCog}
to="/settings"
indent={15}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import React, { useRef, useCallback, useLayoutEffect } from 'react';
import { useDispatch } from 'react-redux';

import escapeRegExp from 'lodash/escapeRegExp';

import { pushModal } from 'loot-core/client/actions';
import { send } from 'loot-core/src/platform/client/fetch';
import {
Expand Down Expand Up @@ -191,8 +189,8 @@ export function TransactionList({
const onNotesTagClick = useCallback(tag => {
onApplyFilter({
field: 'notes',
op: 'matches',
value: `(^|\\s|\\w)${escapeRegExp(tag)}($|\\s|#)`,
op: 'hasTags',
value: tag,
type: 'string',
});
});
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop-electron/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
"promise-retry": "^2.0.1"
},
"devDependencies": {
"@electron/notarize": "2.2.0",
"@electron/notarize": "2.4.0",
"@electron/rebuild": "3.6.0",
"@types/copyfiles": "^2",
"copyfiles": "^2.4.1",
Expand Down
20 changes: 20 additions & 0 deletions packages/loot-core/src/server/accounts/rules.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ describe('Condition', () => {
let cond = new Condition('contains', 'name', 'foo', null, fieldTypes);
expect(cond.eval({ name: null })).toBe(false);

cond = new Condition('matches', 'name', '^fo*$', null, fieldTypes);
expect(cond.eval({ name: null })).toBe(false);

cond = new Condition('oneOf', 'name', ['foo'], null, fieldTypes);
expect(cond.eval({ name: null })).toBe(false);

Expand All @@ -69,6 +72,9 @@ describe('Condition', () => {
cond = new Condition('contains', 'name', 'foo', null, fieldTypes);
expect(cond.eval({ date: '2020-01-01' })).toBe(false);

cond = new Condition('matches', 'name', '^fo*$', null, fieldTypes);
expect(cond.eval({ date: '2020-01-01' })).toBe(false);

spy.mockRestore();
});

Expand Down Expand Up @@ -223,6 +229,20 @@ describe('Condition', () => {
expect(cond.eval({ name: 'bfoo' })).toBe(true);
expect(cond.eval({ name: 'bfo' })).toBe(false);
expect(cond.eval({ name: 'f o o' })).toBe(false);

cond = new Condition('matches', 'name', '^fo*$', null, fieldTypes);
expect(cond.eval({ name: 'bar foo baz' })).toBe(false);
expect(cond.eval({ name: 'bar FOOb' })).toBe(false);
expect(cond.eval({ name: 'foo' })).toBe(true);
expect(cond.eval({ name: 'foob' })).toBe(false);
expect(cond.eval({ name: 'bfoo' })).toBe(false);
expect(cond.eval({ name: 'bfo' })).toBe(false);
expect(cond.eval({ name: 'f o o' })).toBe(false);
});

test('matches handles invalid regex', () => {
const cond = new Condition('matches', 'name', 'fo**', null, fieldTypes);
expect(cond.eval({ name: 'foo' })).toBe(false);
});

test('number validates value', () => {
Expand Down
Loading

0 comments on commit f604be3

Please sign in to comment.