Skip to content

Commit

Permalink
[Typescript] Server event types
Browse files Browse the repository at this point in the history
  • Loading branch information
joel-jeremy committed Jan 7, 2025
1 parent 7c2408d commit 4b97473
Show file tree
Hide file tree
Showing 15 changed files with 153 additions and 74 deletions.
12 changes: 6 additions & 6 deletions packages/desktop-client/src/components/Titlebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ function SyncButton({ style, isMobile = false }: SyncButtonProps) {
>(null);

useEffect(() => {
const unlisten = listen('sync-event', ({ type, subtype, syncDisabled }) => {
if (type === 'start') {
const unlisten = listen('sync-event', event => {
if (event.type === 'start') {
setSyncing(true);
setSyncState(null);
} else {
Expand All @@ -130,19 +130,19 @@ function SyncButton({ style, isMobile = false }: SyncButtonProps) {
}, 200);
}

if (type === 'error') {
if (event.type === 'error') {
// Use the offline state if either there is a network error or
// if this file isn't a "cloud file". You can't sync a local
// file.
if (subtype === 'network') {
if (event.subtype === 'network') {
setSyncState('offline');
} else if (!cloudFileId) {
setSyncState('local');
} else {
setSyncState('error');
}
} else if (type === 'success') {
setSyncState(syncDisabled ? 'disabled' : null);
} else if (event.type === 'success') {
setSyncState(event.syncDisabled ? 'disabled' : null);
}
});

Expand Down
16 changes: 9 additions & 7 deletions packages/desktop-client/src/components/budget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,16 @@ function BudgetInner(props: BudgetInnerProps) {
run();

const unlistens = [
listen('sync-event', ({ type, tables }) => {
if (
type === 'success' &&
(tables.includes('categories') ||
listen('sync-event', event => {
if (event.type === 'success') {
const tables = event.tables;
if (
tables.includes('categories') ||
tables.includes('category_mapping') ||
tables.includes('category_groups'))
) {
loadCategories();
tables.includes('category_groups')
) {
loadCategories();
}
}
}),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,9 @@ function TransactionListWithPreviews({
}, [accountId, dispatch]);

useEffect(() => {
return listen('sync-event', ({ type, tables }) => {
if (type === 'applied') {
return listen('sync-event', event => {
if (event.type === 'applied') {
const tables = event.tables;
if (
tables.includes('transactions') ||
tables.includes('category_mapping') ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ export function CategoryTransactions({
const dateFormat = useDateFormat() || 'MM/dd/yyyy';

useEffect(() => {
return listen('sync-event', ({ type, tables }) => {
if (type === 'applied') {
return listen('sync-event', event => {
if (event.type === 'applied') {
const tables = event.tables;
if (
tables.includes('transactions') ||
tables.includes('category_mapping') ||
Expand Down
18 changes: 10 additions & 8 deletions packages/desktop-client/src/components/mobile/budget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,17 @@ export function Budget() {

init();

const unlisten = listen('sync-event', ({ type, tables }) => {
if (
type === 'success' &&
(tables.includes('categories') ||
const unlisten = listen('sync-event', event => {
if (event.type === 'success') {
const tables = event.tables;
if (
tables.includes('categories') ||
tables.includes('category_mapping') ||
tables.includes('category_groups'))
) {
// TODO: is this loading every time?
dispatch(getCategories());
tables.includes('category_groups')
) {
// TODO: is this loading every time?
dispatch(getCategories());
}
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ export function ManagePayeesWithData({
}
loadData();

const unlisten = listen('sync-event', async ({ type, tables }) => {
if (type === 'applied') {
if (tables.includes('rules')) {
const unlisten = listen('sync-event', async event => {
if (event.type === 'applied') {
if (event.tables.includes('rules')) {
await refetchRuleCounts();
}
}
Expand Down
9 changes: 5 additions & 4 deletions packages/desktop-client/src/global-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,20 @@ export function handleGlobalEvents(actions: BoundActions, store: Store<State>) {
});
});

listen('schedules-offline', ({ payees }) => {
actions.pushModal('schedule-posts-offline-notification', { payees });
listen('schedules-offline', () => {
actions.pushModal('schedule-posts-offline-notification');
});

// This is experimental: we sync data locally automatically when
// data changes from the backend
listen('sync-event', async ({ type, tables }) => {
listen('sync-event', async event => {
// We don't need to query anything until the file is loaded, and
// sync events might come in if the file is being synced before
// being loaded (happens when downloading)
const prefs = store.getState().prefs.local;
if (prefs && prefs.id) {
if (type === 'applied') {
if (event.type === 'applied') {
const tables = event.tables;
if (tables.includes('payees') || tables.includes('payee_mapping')) {
actions.getPayees();
}
Expand Down
15 changes: 9 additions & 6 deletions packages/loot-core/src/client/query-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export class LiveQuery<TResponse = unknown> {
private _data: Data<TResponse>;
private _dependencies: Set<string>;
private _listeners: Array<Listener<TResponse>>;
private _supportedSyncTypes: Set<string>;
private _supportedSyncTypes: Set<'applied' | 'success'>;
private _query: Query;
private _onError: (error: Error) => void;

Expand Down Expand Up @@ -107,8 +107,8 @@ export class LiveQuery<TResponse = unknown> {

// TODO: error types?
this._supportedSyncTypes = options.onlySync
? new Set<string>(['success'])
: new Set<string>(['applied', 'success']);
? new Set(['success'])
: new Set(['applied', 'success']);

if (onData) {
this.addListener(onData);
Expand Down Expand Up @@ -162,15 +162,18 @@ export class LiveQuery<TResponse = unknown> {

protected subscribe = () => {
if (this._unsubscribeSyncEvent == null) {
this._unsubscribeSyncEvent = listen('sync-event', ({ type, tables }) => {
this._unsubscribeSyncEvent = listen('sync-event', event => {
// If the user is doing optimistic updates, they don't want to
// always refetch whenever something changes because it would
// refetch all data after they've already updated the UI. This
// voids the perf benefits of optimistic updates. Allow querys
// to only react to remote syncs. By default, queries will
// always update to all changes.
if (this._supportedSyncTypes.has(type)) {
this.onUpdate(tables);
if (
(event.type === 'applied' || event.type === 'success') &&
this._supportedSyncTypes.has(event.type)
) {
this.onUpdate(event.tables);
}
});
}
Expand Down
20 changes: 10 additions & 10 deletions packages/loot-core/src/client/shared-listeners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,14 @@ import type { Notification } from './state-types/notifications';
export function listenForSyncEvent(actions, store) {
let attemptedSyncRepair = false;

listen('sync-event', info => {
const { type, subtype, meta, tables } = info;

listen('sync-event', event => {
const prefs = store.getState().prefs.local;
if (!prefs || !prefs.id) {
// Do nothing if no budget is loaded
return;
}

if (type === 'success') {
if (event.type === 'success') {
if (attemptedSyncRepair) {
attemptedSyncRepair = false;

Expand All @@ -28,6 +26,8 @@ export function listenForSyncEvent(actions, store) {
});
}

const tables = event.tables;

if (tables.includes('prefs')) {
actions.loadPrefs();
}
Expand All @@ -47,15 +47,15 @@ export function listenForSyncEvent(actions, store) {
if (tables.includes('accounts')) {
actions.getAccounts();
}
} else if (type === 'error') {
} else if (event.type === 'error') {
let notif: Notification | null = null;
const learnMore = t(
'[Learn more](https://actualbudget.org/docs/getting-started/sync/#debugging-sync-issues)',
);
const githubIssueLink =
'https://github.com/actualbudget/actual/issues/new?assignees=&labels=bug&template=bug-report.yml&title=%5BBug%5D%3A+';

switch (subtype) {
switch (event.subtype) {
case 'out-of-sync':
if (attemptedSyncRepair) {
notif = {
Expand Down Expand Up @@ -217,7 +217,7 @@ export function listenForSyncEvent(actions, store) {
break;
case 'encrypt-failure':
case 'decrypt-failure':
if (meta.isMissingKey) {
if (event.meta.isMissingKey) {
notif = {
title: t('Missing encryption key'),
message: t(
Expand Down Expand Up @@ -254,7 +254,7 @@ export function listenForSyncEvent(actions, store) {
}
break;
case 'invalid-schema':
console.trace('invalid-schema', meta);
console.trace('invalid-schema', event.meta);
notif = {
title: t('Update required'),
message: t(
Expand All @@ -265,7 +265,7 @@ export function listenForSyncEvent(actions, store) {
};
break;
case 'apply-failure':
console.trace('apply-failure', meta);
console.trace('apply-failure', event.meta);
notif = {
message: t(
'We couldn’t apply that change to the database. Please report this as a bug by [opening a Github issue]({{githubIssueLink}}).',
Expand All @@ -289,7 +289,7 @@ export function listenForSyncEvent(actions, store) {
};
break;
default:
console.trace('unknown error', info);
console.trace('unknown error', event);
notif = {
message: t(
'We had problems syncing your changes. Please report this as a bug by [opening a Github issue]({{githubIssueLink}}).',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export type Init = typeof init;

export function send<K extends keyof ServerEvents>(
type: K,
args?: ServerEvents[k],
args?: ServerEvents[K],
): void;
export type Send = typeof send;

Expand Down
4 changes: 2 additions & 2 deletions packages/loot-core/src/server/accounts/transactions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @ts-strict-ignore
import * as connection from '../../platform/server/connection';
import { Diff } from '../../shared/util';
import { TransactionEntity } from '../../types/models';
import { PayeeEntity, TransactionEntity } from '../../types/models';
import * as db from '../db';
import { incrFetch, whereIn } from '../db/util';
import { batchMessages } from '../sync';
Expand Down Expand Up @@ -55,7 +55,7 @@ export async function batchUpdateTransactions({
? await idsWithChildren(deleted.map(d => d.id))
: [];

const oldPayees = new Set();
const oldPayees = new Set<PayeeEntity['id']>();
const accounts = await db.all('SELECT * FROM accounts WHERE tombstone = 0');

// We need to get all the payees of updated transactions _before_
Expand Down
10 changes: 8 additions & 2 deletions packages/loot-core/src/server/app.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
// @ts-strict-ignore
import mitt from 'mitt';
import mitt, { type Emitter } from 'mitt';

import { captureException } from '../platform/exceptions';
import { ServerEvents } from '../types/server-events';

// This is a simple helper abstraction for defining methods exposed to
// the client. It doesn't do much, but checks for naming conflicts and
// makes it cleaner to combine methods. We call a group of related
// methods an "app".

type Events = {
sync: ServerEvents['sync-event'];
'load-budget': { id: string };
};

class App<Handlers> {
events;
events: Emitter<Events>;
handlers: Handlers;
services;
unlistenServices;
Expand Down
4 changes: 2 additions & 2 deletions packages/loot-core/src/server/main-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ import { createApp } from './app';
// Main app
export const app = createApp<Handlers>();

app.events.on('sync', info => {
connection.send('sync-event', info);
app.events.on('sync', event => {
connection.send('sync-event', event);
});
4 changes: 2 additions & 2 deletions packages/loot-core/src/server/schedules/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ async function advanceSchedulesService(syncSuccess) {
}

if (failedToPost.length > 0) {
connection.send('schedules-offline', { payees: failedToPost });
connection.send('schedules-offline');
} else if (didPost) {
// This forces a full refresh of transactions because it
// simulates them coming in from a full sync. This not a
Expand All @@ -542,7 +542,7 @@ async function advanceSchedulesService(syncSuccess) {
connection.send('sync-event', {
type: 'success',
tables: ['transactions'],
syncDisabled: 'false',
syncDisabled: false,
});
}
}
Expand Down
Loading

0 comments on commit 4b97473

Please sign in to comment.