From 94255ffb9d075430742cacd41cb2ca3fccf2eb73 Mon Sep 17 00:00:00 2001 From: RunasSudo Date: Mon, 9 Jun 2025 19:36:15 +1000 Subject: [PATCH] Allow configuring frontend plugins --- docs/demo.sql | 1 + src/db.ts | 8 +++- src/main.ts | 41 ++++++++++----------- src/pages/HomeView.vue | 21 +++++++---- src/plugin.ts | 28 ++++++++++++++ src/plugins/austax/AdvancedReportsLinks.vue | 22 +++++++++++ src/plugins/austax/DataSourcesLinks.vue | 21 +++++++++++ src/plugins/austax/GeneralReportsLinks.vue | 20 ++++++++++ src/plugins/austax/plugin.ts | 40 ++++++++++++++++++++ src/registry.ts | 13 ++++--- 10 files changed, 180 insertions(+), 35 deletions(-) create mode 100644 src/plugin.ts create mode 100644 src/plugins/austax/AdvancedReportsLinks.vue create mode 100644 src/plugins/austax/DataSourcesLinks.vue create mode 100644 src/plugins/austax/GeneralReportsLinks.vue create mode 100644 src/plugins/austax/plugin.ts diff --git a/docs/demo.sql b/docs/demo.sql index 581e532..1338d32 100644 --- a/docs/demo.sql +++ b/docs/demo.sql @@ -39,6 +39,7 @@ INSERT INTO metadata VALUES(1,'version','3'); INSERT INTO metadata VALUES(2,'eofy_date','2025-06-30'); INSERT INTO metadata VALUES(3,'reporting_commodity','$'); INSERT INTO metadata VALUES(4,'amount_dps','2'); +INSERT INTO metadata VALUES(5,'plugins',''); CREATE TABLE postings ( id INTEGER NOT NULL, transaction_id INTEGER, diff --git a/src/db.ts b/src/db.ts index 641ac0e..240d3fc 100644 --- a/src/db.ts +++ b/src/db.ts @@ -1,5 +1,5 @@ /* - DrCr: Web-based double-entry bookkeeping framework + DrCr: Double-entry bookkeeping framework Copyright (C) 2022-2025 Lee Yingtong Li (RunasSudo) This program is free software: you can redistribute it and/or modify @@ -39,6 +39,7 @@ export const db = reactive({ eofy_date: null! as string, reporting_commodity: null! as string, dps: null! as number, + plugins: null! as string[], }, init: async function(filename: string | null): Promise { @@ -77,6 +78,7 @@ export const db = reactive({ this.metadata.eofy_date = metadataObject.eofy_date; this.metadata.reporting_commodity = metadataObject.reporting_commodity; this.metadata.dps = parseInt(metadataObject.amount_dps); + this.metadata.plugins = metadataObject.plugins.length > 0 ? metadataObject.plugins.split(';') : []; } }, @@ -114,6 +116,10 @@ export async function createNewDatabase(filename: string, eofy_date: string, rep `INSERT INTO metadata (key, value) VALUES (?, ?)`, ['amount_dps', dps.toString()] // Manually call .toString() to format as int, otherwise sqlx formats as float ); + await transaction.execute( + `INSERT INTO metadata (key, value) VALUES (?, ?)`, + ['plugins', ''] + ); await transaction.commit(); } diff --git a/src/main.ts b/src/main.ts index 699f971..772c91d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,5 @@ /* - DrCr: Web-based double-entry bookkeeping framework + DrCr: Double-entry bookkeeping framework Copyright (C) 2022-2025 Lee Yingtong Li (RunasSudo) This program is free software: you can redistribute it and/or modify @@ -20,16 +20,26 @@ import { invoke } from '@tauri-apps/api/core'; import { WebviewWindow } from '@tauri-apps/api/webviewWindow'; import { createApp } from 'vue'; -import { createRouter, createWebHistory } from 'vue-router'; +import { RouteRecordRaw, createRouter, createWebHistory } from 'vue-router'; import App from './App.vue'; - import { db } from './db.ts'; import { handleCriticalError } from './error.ts'; +import austax from './plugins/austax/plugin.ts'; async function initApp() { + // Init state + const dbFilename: string = await invoke('get_open_filename'); + if (dbFilename !== null) { + try { + await db.init(dbFilename); // Ensure all metadata cached before loading Vue + } catch (err) { + handleCriticalError(err); + } + } + // Init router - const routes = [ + let routes: RouteRecordRaw[] = [ { path: '/', name: 'index', component: () => import('./pages/HomeView.vue') }, { path: '/balance-assertions', name: 'balance-assertions', component: () => import('./pages/BalanceAssertionsView.vue') }, { path: '/balance-assertions/edit/:id', name: 'balance-assertions-edit', component: () => import('./pages/EditBalanceAssertionView.vue') }, @@ -46,29 +56,18 @@ async function initApp() { { path: '/statement-lines/import', name: 'import-statement', component: () => import('./pages/ImportStatementView.vue') }, { path: '/transactions/:account', name: 'transactions', component: () => import('./pages/TransactionsView.vue') }, { path: '/trial-balance', name: 'trial-balance', component: () => import('./reports/TrialBalanceReport.vue') }, - // TODO: Generate this list dynamically - { path: '/austax/cgt-adjustments', name: 'cgt-adjustments', component: () => import('./plugins/austax/CGTAdjustmentsView.vue') }, - { path: '/austax/cgt-adjustments/edit/:id', name: 'cgt-adjustments-edit', component: () => import('./plugins/austax/EditCGTAdjustmentView.vue') }, - { path: '/austax/cgt-adjustments/new', name: 'cgt-adjustments-new', component: () => import('./plugins/austax/NewCGTAdjustmentView.vue') }, - { path: '/austax/cgt-adjustments/multinew', name: 'cgt-adjustments-multinew', component: () => import('./plugins/austax/MultiNewCGTAdjustmentView.vue') }, - { path: '/austax/cgt-assets', name: 'cgt-assets', component: () => import('./plugins/austax/CGTAssetsView.vue') }, - { path: '/austax/tax-summary', name: 'tax-summary', component: () => import('./plugins/austax/TaxSummaryReport.vue') }, ]; + + // Init plugin routes + if (db.metadata.plugins.indexOf('austax') >= 0) { + routes.push(...austax.getRoutes()); + } + const router = createRouter({ history: createWebHistory(), routes, }); - // Init state - const dbFilename: string = await invoke('get_open_filename'); - if (dbFilename !== null) { - try { - await db.init(dbFilename); // Ensure all metadata cached before loading Vue - } catch (err) { - handleCriticalError(err); - } - } - // Create Vue app createApp(App).use(router).mount('#app'); } diff --git a/src/pages/HomeView.vue b/src/pages/HomeView.vue index 0ca7b8f..0d72151 100644 --- a/src/pages/HomeView.vue +++ b/src/pages/HomeView.vue @@ -1,5 +1,5 @@ + + diff --git a/src/plugin.ts b/src/plugin.ts new file mode 100644 index 0000000..f2bc11b --- /dev/null +++ b/src/plugin.ts @@ -0,0 +1,28 @@ +/* + DrCr: Double-entry bookkeeping framework + Copyright (C) 2022-2025 Lee Yingtong Li (RunasSudo) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +import { Component } from 'vue'; +import { RouteRecordRaw } from 'vue-router'; + +export interface Plugin { + getAccountKinds: () => Promise<[string, string][]>, + getAdvancedReportsLinks: () => Component, + getDataSourcesLinks: () => Component, + getGeneralReportsLinks: () => Component, + getRoutes: () => RouteRecordRaw[], +} diff --git a/src/plugins/austax/AdvancedReportsLinks.vue b/src/plugins/austax/AdvancedReportsLinks.vue new file mode 100644 index 0000000..cecbcbd --- /dev/null +++ b/src/plugins/austax/AdvancedReportsLinks.vue @@ -0,0 +1,22 @@ + + + diff --git a/src/plugins/austax/DataSourcesLinks.vue b/src/plugins/austax/DataSourcesLinks.vue new file mode 100644 index 0000000..c2d0702 --- /dev/null +++ b/src/plugins/austax/DataSourcesLinks.vue @@ -0,0 +1,21 @@ + + + diff --git a/src/plugins/austax/GeneralReportsLinks.vue b/src/plugins/austax/GeneralReportsLinks.vue new file mode 100644 index 0000000..b5a6fb8 --- /dev/null +++ b/src/plugins/austax/GeneralReportsLinks.vue @@ -0,0 +1,20 @@ + + + diff --git a/src/plugins/austax/plugin.ts b/src/plugins/austax/plugin.ts new file mode 100644 index 0000000..899777f --- /dev/null +++ b/src/plugins/austax/plugin.ts @@ -0,0 +1,40 @@ +/* + DrCr: Double-entry bookkeeping framework + Copyright (C) 2022-2025 Lee Yingtong Li (RunasSudo) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +import { getAccountKinds } from './account_kinds.ts'; +import DataSourcesLinks from './DataSourcesLinks.vue'; +import GeneralReportsLinks from './GeneralReportsLinks.vue'; +import AdvancedReportsLinks from './AdvancedReportsLinks.vue'; +import { Plugin } from '../../plugin.ts'; + +export default { + 'getAccountKinds': getAccountKinds, + + getDataSourcesLinks: () => DataSourcesLinks, + getGeneralReportsLinks: () => GeneralReportsLinks, + getAdvancedReportsLinks: () => AdvancedReportsLinks, + + getRoutes: () => [ + { path: '/austax/cgt-adjustments', name: 'cgt-adjustments', component: () => import('./CGTAdjustmentsView.vue') }, + { path: '/austax/cgt-adjustments/edit/:id', name: 'cgt-adjustments-edit', component: () => import('./EditCGTAdjustmentView.vue') }, + { path: '/austax/cgt-adjustments/new', name: 'cgt-adjustments-new', component: () => import('./NewCGTAdjustmentView.vue') }, + { path: '/austax/cgt-adjustments/multinew', name: 'cgt-adjustments-multinew', component: () => import('./MultiNewCGTAdjustmentView.vue') }, + { path: '/austax/cgt-assets', name: 'cgt-assets', component: () => import('./CGTAssetsView.vue') }, + { path: '/austax/tax-summary', name: 'tax-summary', component: () => import('./TaxSummaryReport.vue') }, + ], +} as Plugin; diff --git a/src/registry.ts b/src/registry.ts index bf2b007..cd30350 100644 --- a/src/registry.ts +++ b/src/registry.ts @@ -1,6 +1,6 @@ /* - DrCr: Web-based double-entry bookkeeping framework - Copyright (C) 2022–2024 Lee Yingtong Li (RunasSudo) + DrCr: Double-entry bookkeeping framework + Copyright (C) 2022-2025 Lee Yingtong Li (RunasSudo) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -16,7 +16,8 @@ along with this program. If not, see . */ -import * as austax from './plugins/austax/account_kinds.ts'; +import { db } from './db.ts'; +import austax from './plugins/austax/plugin.ts'; export const drcrAccountKinds: [string, string][] = [ ['drcr.asset', 'Asset'], @@ -29,8 +30,10 @@ export const drcrAccountKinds: [string, string][] = [ export async function getAccountKinds() { const accountKinds = [...drcrAccountKinds]; - // FIXME: Make this customisable - accountKinds.push(...await austax.getAccountKinds()); + // Add plugin account kinds + if (db.metadata.plugins.indexOf('austax') >= 0) { + accountKinds.push(...await austax.getAccountKinds()); + } return accountKinds; }