diff --git a/packages/api/methods.test.ts b/packages/api/methods.test.ts index 9a9e2fb9ed31c41513596fd5482f2ba5b10395fd..8e0a9b586fa677f0dc68ed7641e9dc3ed8e33a29 100644 --- a/packages/api/methods.test.ts +++ b/packages/api/methods.test.ts @@ -58,6 +58,19 @@ describe('API CRUD operations', () => { await api.loadBudget(budgetName); }); + // api: getBudgets + test('getBudgets', async () => { + const budgets = await api.getBudgets(); + expect(budgets).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: 'test-budget', + name: 'Default Test Db', + }), + ]), + ); + }); + // apis: getCategoryGroups, createCategoryGroup, updateCategoryGroup, deleteCategoryGroup test('CategoryGroups: successfully update category groups', async () => { const month = '2023-10'; diff --git a/packages/api/methods.ts b/packages/api/methods.ts index cc25bfe3e40983dbfdabded907f37c8f55f699ec..124d5d66628d7928d9c18eb02f1143bd7ac1f928 100644 --- a/packages/api/methods.ts +++ b/packages/api/methods.ts @@ -31,6 +31,10 @@ export async function downloadBudget(syncId, { password }: { password? } = {}) { return send('api/download-budget', { syncId, password }); } +export async function getBudgets() { + return send('api/get-budgets'); +} + export async function sync() { return send('api/sync'); } diff --git a/packages/loot-core/src/server/api-models.ts b/packages/loot-core/src/server/api-models.ts index 69be7a40a23456cd743193eb863121545538c8c4..ebd68e8d47f7f7f009fd43e530b4ffb3aa23a8f9 100644 --- a/packages/loot-core/src/server/api-models.ts +++ b/packages/loot-core/src/server/api-models.ts @@ -1,3 +1,4 @@ +import { Budget } from '../types/budget'; import type { AccountEntity, CategoryEntity, @@ -5,6 +6,7 @@ import type { PayeeEntity, } from '../types/models'; +import { RemoteFile } from './cloud-storage'; import * as models from './models'; export type APIAccountEntity = Pick<AccountEntity, 'id' | 'name'> & { @@ -114,3 +116,39 @@ export const payeeModel = { return payee as PayeeEntity; }, }; + +export type APIFileEntity = Omit<RemoteFile, 'deleted' | 'fileId'> & { + id?: string; + cloudFileId: string; + state?: 'remote'; +}; + +export const remoteFileModel = { + toExternal(file: RemoteFile): APIFileEntity | null { + if (file.deleted) { + return null; + } + return { + cloudFileId: file.fileId, + state: 'remote', + groupId: file.groupId, + name: file.name, + encryptKeyId: file.encryptKeyId, + hasKey: file.hasKey, + }; + }, + + fromExternal(file: APIFileEntity) { + return { deleted: false, fileId: file.cloudFileId, ...file } as RemoteFile; + }, +}; + +export const budgetModel = { + toExternal(file: Budget): APIFileEntity { + return file as APIFileEntity; + }, + + fromExternal(file: APIFileEntity) { + return file as Budget; + }, +}; diff --git a/packages/loot-core/src/server/api.ts b/packages/loot-core/src/server/api.ts index fe670152ad4389eb9d9dd90d66b4f5226f1ab196..f2bbe5f42293b2879ee16a97c133b48ffcf86948 100644 --- a/packages/loot-core/src/server/api.ts +++ b/packages/loot-core/src/server/api.ts @@ -22,9 +22,11 @@ import { ServerHandlers } from '../types/server-handlers'; import { addTransactions } from './accounts/sync'; import { accountModel, + budgetModel, categoryModel, categoryGroupModel, payeeModel, + remoteFileModel, } from './api-models'; import { runQuery as aqlQuery } from './aql'; import * as cloudStorage from './cloud-storage'; @@ -226,6 +228,15 @@ handlers['api/download-budget'] = async function ({ syncId, password }) { await handlers['load-budget']({ id: result.id }); }; +handlers['api/get-budgets'] = async function () { + const budgets = await handlers['get-budgets'](); + const files = (await handlers['get-remote-files']()) || []; + return [ + ...budgets.map(file => budgetModel.toExternal(file)), + ...files.map(file => remoteFileModel.toExternal(file)).filter(file => file), + ]; +}; + handlers['api/sync'] = async function () { const { id } = prefs.getPrefs(); const result = await handlers['sync-budget'](); diff --git a/packages/loot-core/src/types/api-handlers.d.ts b/packages/loot-core/src/types/api-handlers.d.ts index edd89582ddc3624f5eb679f0282895baa725b3bb..d8f23ae5be2db2efbc2071ba1d535844c370c552 100644 --- a/packages/loot-core/src/types/api-handlers.d.ts +++ b/packages/loot-core/src/types/api-handlers.d.ts @@ -3,6 +3,7 @@ import type { APIAccountEntity, APICategoryEntity, APICategoryGroupEntity, + APIFileEntity, APIPayeeEntity, } from '../server/api-models'; @@ -23,6 +24,8 @@ export interface ApiHandlers { password?: string; }) => Promise<void>; + 'api/get-budgets': () => Promise<APIFileEntity[]>; + 'api/start-import': (arg: { budgetName: string }) => Promise<void>; 'api/finish-import': () => Promise<void>; diff --git a/upcoming-release-notes/2928.md b/upcoming-release-notes/2928.md new file mode 100644 index 0000000000000000000000000000000000000000..3c3490058c9eee4f8a13c5ab3a728e1b4ac0c2c0 --- /dev/null +++ b/upcoming-release-notes/2928.md @@ -0,0 +1,6 @@ +--- +category: Enhancements +authors: [psybers] +--- + +API: add getBudgets() method to list all local/remote budgets.