mirror of
https://github.com/actualbudget/actual.git
synced 2026-10-12 02:10:19 +00:00
chore: replace Prettier with oxfmt and add oxlint (#6259)
* chore: replace Prettier with oxfmt and add oxlint - Replace Prettier with oxfmt (Prettier-compatible formatter from OXC project) - Add oxlint for fast linting alongside ESLint - Add eslint-plugin-oxlint to disable ESLint rules covered by oxlint - Update lint scripts to run oxfmt, oxlint, then eslint - Update lint-staged configuration for pre-commit hooks - Create .oxfmtrc.json and .oxlintrc.json configuration files - Remove .prettierrc.json and .prettierignore - Reformat codebase with oxfmt * chore: update dependencies in yarn.lock * chore: update oxlint configuration to disable additional rules * chore: update oxfmt and oxlint configurations, enhance test readability
This commit is contained in:
@@ -4,7 +4,6 @@
|
||||
// 1. Identify the migrations in packages/loot-core/migrations/* on `master` and HEAD
|
||||
// 2. Make sure that any new migrations on HEAD are dated after the latest migration on `master`.
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { spawnSync } = require('child_process');
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"arrowParens": "avoid",
|
||||
"printWidth": 80
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||
"plugins": ["react", "typescript", "import", "jsx-a11y"],
|
||||
"rules": {
|
||||
// TODO fix all these and re-enable
|
||||
"import/namespace": "off",
|
||||
"jsx-a11y/alt-text": "off",
|
||||
"jsx-a11y/aria-role": "off",
|
||||
"jsx-a11y/click-events-have-key-events": "off",
|
||||
"jsx-a11y/label-has-associated-control": "off",
|
||||
"jsx-a11y/prefer-tag-over-role": "off",
|
||||
"jsx-a11y/role-has-required-aria-props": "off",
|
||||
"jsx-a11y/tabindex-no-positive": "off",
|
||||
"no-async-promise-executor": "off",
|
||||
"no-autofocus": "off",
|
||||
"no-constant-condition": "off",
|
||||
"no-empty-pattern": "off",
|
||||
"no-extra-boolean-cast": "off",
|
||||
"no-unused-vars": "off",
|
||||
"no-useless-catch": "off",
|
||||
"react/jsx-key": "off",
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
// TODO: fix the issues in these files
|
||||
"files": [
|
||||
"packages/component-library/src/Menu.tsx",
|
||||
"packages/desktop-client/src/components/accounts/Account.jsx",
|
||||
"packages/desktop-client/src/components/accounts/MobileAccount.jsx",
|
||||
"packages/desktop-client/src/components/accounts/MobileAccounts.jsx",
|
||||
"packages/desktop-client/src/components/budget/BudgetCategories.jsx",
|
||||
"packages/desktop-client/src/components/budget/BudgetSummaries.tsx",
|
||||
"packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx",
|
||||
"packages/desktop-client/src/components/budget/envelope/HoldMenu.tsx",
|
||||
"packages/desktop-client/src/components/budget/envelope/TransferMenu.tsx",
|
||||
"packages/desktop-client/src/components/budget/index.tsx",
|
||||
"packages/desktop-client/src/components/budget/MobileBudget.tsx",
|
||||
"packages/desktop-client/src/components/FinancesApp.tsx",
|
||||
"packages/desktop-client/src/components/GlobalKeys.ts",
|
||||
"packages/desktop-client/src/components/LoggedInUser.tsx",
|
||||
"packages/desktop-client/src/components/manager/ManagementApp.jsx",
|
||||
"packages/desktop-client/src/components/manager/subscribe/common.tsx",
|
||||
"packages/desktop-client/src/components/ManageRules.tsx",
|
||||
"packages/desktop-client/src/components/mobile/MobileAmountInput.jsx",
|
||||
"packages/desktop-client/src/components/mobile/MobileNavTabs.tsx",
|
||||
"packages/desktop-client/src/components/Modals.tsx",
|
||||
"packages/desktop-client/src/components/modals/EditRule.jsx",
|
||||
"packages/desktop-client/src/components/modals/ImportTransactions.jsx",
|
||||
"packages/desktop-client/src/components/modals/ImportTransactionsModal/ImportTransactionsModal.tsx",
|
||||
"packages/desktop-client/src/components/modals/MergeUnusedPayees.jsx",
|
||||
"packages/desktop-client/src/components/Notifications.tsx",
|
||||
"packages/desktop-client/src/components/payees/ManagePayees.jsx",
|
||||
"packages/desktop-client/src/components/payees/ManagePayeesWithData.jsx",
|
||||
"packages/desktop-client/src/components/payees/PayeeTable.tsx",
|
||||
"packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTable.tsx",
|
||||
"packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableTotals.tsx",
|
||||
"packages/desktop-client/src/components/reports/reports/CashFlowCard.jsx",
|
||||
"packages/desktop-client/src/components/reports/reports/CustomReport.jsx",
|
||||
"packages/desktop-client/src/components/reports/reports/CustomReport.tsx",
|
||||
"packages/desktop-client/src/components/reports/reports/NetWorthCard.jsx",
|
||||
"packages/desktop-client/src/components/reports/SaveReportName.tsx",
|
||||
"packages/desktop-client/src/components/reports/useReport.ts",
|
||||
"packages/desktop-client/src/components/schedules/ScheduleDetails.jsx",
|
||||
"packages/desktop-client/src/components/schedules/ScheduleEditModal.tsx",
|
||||
"packages/desktop-client/src/components/schedules/SchedulesTable.tsx",
|
||||
"packages/desktop-client/src/components/select/DateSelect.tsx",
|
||||
"packages/desktop-client/src/components/sidebar/Tools.tsx",
|
||||
"packages/desktop-client/src/components/sort.tsx",
|
||||
"packages/desktop-client/src/hooks/useEffectAfterMount.ts",
|
||||
"packages/desktop-client/src/hooks/useQuery.ts",
|
||||
],
|
||||
"rules": {
|
||||
"react-hooks/exhaustive-deps": "off",
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
sync_pb.*
|
||||
packages/api/app/bundle.api.js
|
||||
packages/api/app/stats.json
|
||||
packages/api/dist
|
||||
packages/api/@types
|
||||
packages/api/migrations
|
||||
packages/crdt/dist
|
||||
packages/component-library/src/icons/**/*
|
||||
packages/desktop-client/bundle.browser.js
|
||||
packages/desktop-client/stats.json
|
||||
packages/desktop-client/.swc/
|
||||
packages/desktop-client/build/
|
||||
packages/desktop-client/dev-dist/
|
||||
packages/desktop-client/locale/
|
||||
packages/desktop-client/build-electron/
|
||||
packages/desktop-client/build-stats/
|
||||
packages/desktop-client/public/kcab/
|
||||
packages/desktop-client/public/data/
|
||||
packages/desktop-client/**/node_modules/*
|
||||
packages/desktop-client/node_modules/
|
||||
packages/desktop-client/test-results/
|
||||
packages/desktop-client/playwright-report/
|
||||
packages/desktop-electron/client-build/
|
||||
packages/desktop-electron/build/
|
||||
packages/desktop-electron/dist/
|
||||
packages/loot-core/**/node_modules/*
|
||||
packages/loot-core/**/lib-dist/*
|
||||
packages/loot-core/**/proto/*
|
||||
packages/sync-server/coverage/
|
||||
packages/sync-server/user-files/
|
||||
packages/sync-server/server-files/
|
||||
.yarn/*
|
||||
upcoming-release-notes/*
|
||||
|
||||
# temporary
|
||||
packages/docs/*
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
+4
-48
@@ -2,6 +2,7 @@ import tsParser from '@typescript-eslint/parser';
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import pluginImport from 'eslint-plugin-import';
|
||||
import pluginJSXA11y from 'eslint-plugin-jsx-a11y';
|
||||
import oxlint from 'eslint-plugin-oxlint';
|
||||
import pluginReact from 'eslint-plugin-react';
|
||||
import pluginReactHooks from 'eslint-plugin-react-hooks';
|
||||
import pluginTypescriptPaths from 'eslint-plugin-typescript-paths';
|
||||
@@ -721,54 +722,6 @@ export default defineConfig(
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// TODO: fix the issues in these files
|
||||
files: [
|
||||
'packages/desktop-client/src/components/accounts/Account.jsx',
|
||||
'packages/desktop-client/src/components/accounts/MobileAccount.jsx',
|
||||
'packages/desktop-client/src/components/accounts/MobileAccounts.jsx',
|
||||
'packages/desktop-client/src/components/budget/BudgetCategories.jsx',
|
||||
'packages/desktop-client/src/components/budget/BudgetSummaries.tsx',
|
||||
'packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx',
|
||||
'packages/desktop-client/src/components/budget/index.tsx',
|
||||
'packages/desktop-client/src/components/budget/MobileBudget.tsx',
|
||||
'packages/desktop-client/src/components/budget/envelope/HoldMenu.tsx',
|
||||
'packages/desktop-client/src/components/budget/envelope/TransferMenu.tsx',
|
||||
'packages/component-library/src/Menu.tsx',
|
||||
'packages/desktop-client/src/components/FinancesApp.tsx',
|
||||
'packages/desktop-client/src/components/GlobalKeys.ts',
|
||||
'packages/desktop-client/src/components/LoggedInUser.tsx',
|
||||
'packages/desktop-client/src/components/manager/ManagementApp.jsx',
|
||||
'packages/desktop-client/src/components/manager/subscribe/common.tsx',
|
||||
'packages/desktop-client/src/components/ManageRules.tsx',
|
||||
'packages/desktop-client/src/components/mobile/MobileAmountInput.jsx',
|
||||
'packages/desktop-client/src/components/mobile/MobileNavTabs.tsx',
|
||||
'packages/desktop-client/src/components/Modals.tsx',
|
||||
'packages/desktop-client/src/components/modals/EditRule.jsx',
|
||||
'packages/desktop-client/src/components/modals/ImportTransactions.jsx',
|
||||
'packages/desktop-client/src/components/modals/MergeUnusedPayees.jsx',
|
||||
'packages/desktop-client/src/components/Notifications.tsx',
|
||||
'packages/desktop-client/src/components/payees/ManagePayees.jsx',
|
||||
'packages/desktop-client/src/components/payees/ManagePayeesWithData.jsx',
|
||||
'packages/desktop-client/src/components/payees/PayeeTable.tsx',
|
||||
'packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTable.tsx',
|
||||
'packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableTotals.tsx',
|
||||
'packages/desktop-client/src/components/reports/reports/CashFlowCard.jsx',
|
||||
'packages/desktop-client/src/components/reports/reports/CustomReport.jsx',
|
||||
'packages/desktop-client/src/components/reports/reports/NetWorthCard.jsx',
|
||||
'packages/desktop-client/src/components/reports/SaveReportName.tsx',
|
||||
'packages/desktop-client/src/components/reports/useReport.ts',
|
||||
'packages/desktop-client/src/components/schedules/ScheduleDetails.jsx',
|
||||
'packages/desktop-client/src/components/schedules/SchedulesTable.tsx',
|
||||
'packages/desktop-client/src/components/select/DateSelect.tsx',
|
||||
'packages/desktop-client/src/components/sidebar/Tools.tsx',
|
||||
'packages/desktop-client/src/components/sort.tsx',
|
||||
],
|
||||
|
||||
rules: {
|
||||
'react-hooks/exhaustive-deps': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'eslint.config.mjs',
|
||||
@@ -811,4 +764,7 @@ export default defineConfig(
|
||||
'import/no-default-export': 'off',
|
||||
},
|
||||
},
|
||||
// Disable ESLint rules that are already covered by oxlint
|
||||
// This must be at the end to override previous rule configurations
|
||||
...oxlint.configs['flat/recommended'],
|
||||
);
|
||||
|
||||
+11
-7
@@ -51,8 +51,8 @@
|
||||
"vrt:docker": "./bin/run-vrt",
|
||||
"rebuild-electron": "./node_modules/.bin/electron-rebuild -m ./packages/loot-core",
|
||||
"rebuild-node": "yarn workspace loot-core rebuild",
|
||||
"lint": "prettier --check . && eslint . --max-warnings 0",
|
||||
"lint:fix": "prettier --check --write . && eslint . --max-warnings 0 --fix",
|
||||
"lint": "oxfmt --check . && oxlint --deny-warnings && eslint . --max-warnings 0",
|
||||
"lint:fix": "oxfmt . && oxlint --deny-warnings --fix && eslint . --max-warnings 0 --fix",
|
||||
"install:server": "yarn workspaces focus @actual-app/sync-server --production",
|
||||
"typecheck": "yarn tsc --incremental && tsc-strict",
|
||||
"jq": "./node_modules/node-jq/bin/jq",
|
||||
@@ -65,10 +65,10 @@
|
||||
"@typescript-eslint/parser": "^8.46.4",
|
||||
"cross-env": "^10.1.0",
|
||||
"eslint": "^9.39.1",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-import-resolver-typescript": "^4.4.4",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||
"eslint-plugin-oxlint": "^1.30.0",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-typescript-paths": "^0.0.33",
|
||||
@@ -80,8 +80,9 @@
|
||||
"minimatch": "^10.1.1",
|
||||
"node-jq": "^6.3.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"oxfmt": "^0.15.0",
|
||||
"oxlint": "^1.30.0",
|
||||
"p-limit": "^7.2.0",
|
||||
"prettier": "^3.6.2",
|
||||
"prompts": "^2.4.2",
|
||||
"source-map-support": "^0.5.21",
|
||||
"ts-node": "^10.9.2",
|
||||
@@ -98,9 +99,12 @@
|
||||
"yarn": "^4.9.1"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,mjs,jsx,ts,tsx,md,json,yml}": [
|
||||
"eslint --fix",
|
||||
"prettier --write"
|
||||
"*.{js,mjs,jsx,ts,tsx,md,json,yml,yaml}": [
|
||||
"oxfmt --no-error-on-unmatched-pattern"
|
||||
],
|
||||
"*.{js,mjs,jsx,ts,tsx}": [
|
||||
"oxlint --deny-warnings --fix",
|
||||
"eslint --max-warnings 0 --fix"
|
||||
]
|
||||
},
|
||||
"packageManager": "[email protected]",
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { type Config } from '@svgr/core';
|
||||
|
||||
const tmpl: Config['template'] = ({ imports, interfaces, componentName, props, jsx }, { tpl }) => {
|
||||
const tmpl: Config['template'] = (
|
||||
{ imports, interfaces, componentName, props, jsx },
|
||||
{ tpl },
|
||||
) => {
|
||||
return tpl`
|
||||
${imports};
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ protoc --plugin="protoc-gen-ts=../../node_modules/.bin/protoc-gen-ts" \
|
||||
--proto_path=src/proto \
|
||||
sync.proto
|
||||
|
||||
../../node_modules/.bin/prettier --write src/proto/*.d.ts
|
||||
../../node_modules/.bin/oxfmt src/proto/*.d.ts
|
||||
|
||||
for file in src/proto/*.d.ts; do
|
||||
{ echo "/* eslint-disable @typescript-eslint/no-namespace */"; sed 's/export class/export declare class/g' "$file"; } > "${file%.d.ts}.ts"
|
||||
|
||||
+443
-531
File diff suppressed because it is too large
Load Diff
@@ -320,9 +320,9 @@ export const downloadBudget = createAppAsyncThunk(
|
||||
const opts = {
|
||||
hasExistingKey: Boolean(
|
||||
error.meta &&
|
||||
typeof error.meta === 'object' &&
|
||||
'isMissingKey' in error.meta &&
|
||||
error.meta.isMissingKey,
|
||||
typeof error.meta === 'object' &&
|
||||
'isMissingKey' in error.meta &&
|
||||
error.meta.isMissingKey,
|
||||
),
|
||||
cloudFileId,
|
||||
onSuccess: () => {
|
||||
|
||||
@@ -132,7 +132,7 @@ function AppInner() {
|
||||
|
||||
initAll().catch(showErrorBoundary);
|
||||
// Removed cloudFileId & t from dependencies to prevent hard crash when closing budget in Electron
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [dispatch, showErrorBoundary]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -70,7 +70,7 @@ export function MobileNavTabs() {
|
||||
config: canceled ? config.wobbly : config.stiff,
|
||||
});
|
||||
},
|
||||
[api, OPEN_FULL_Y],
|
||||
[api],
|
||||
);
|
||||
|
||||
const openDefault = useCallback(
|
||||
@@ -82,7 +82,7 @@ export function MobileNavTabs() {
|
||||
config: { ...config.stiff, velocity },
|
||||
});
|
||||
},
|
||||
[api, OPEN_DEFAULT_Y],
|
||||
[api],
|
||||
);
|
||||
|
||||
const hide = useCallback(
|
||||
@@ -94,7 +94,7 @@ export function MobileNavTabs() {
|
||||
config: { ...config.stiff, velocity },
|
||||
});
|
||||
},
|
||||
[api, HIDDEN_Y],
|
||||
[api],
|
||||
);
|
||||
|
||||
const navTabs = [
|
||||
|
||||
@@ -381,7 +381,7 @@ function SelectedTransactionsFloatingActionBar({
|
||||
const canMerge = useMemo(() => {
|
||||
return Boolean(
|
||||
twoTransactions &&
|
||||
twoTransactions[0].amount === twoTransactions[1].amount,
|
||||
twoTransactions[0].amount === twoTransactions[1].amount,
|
||||
);
|
||||
}, [twoTransactions]);
|
||||
|
||||
|
||||
@@ -95,8 +95,7 @@ export function CreateEncryptionKeyModal({
|
||||
We will generate a key based on a password and use it to
|
||||
encrypt from now on.{' '}
|
||||
<strong>This requires a sync reset</strong> and all other
|
||||
devices will have to revert to this version of your
|
||||
data.{' '}
|
||||
devices will have to revert to this version of your data.{' '}
|
||||
</Trans>
|
||||
<Link
|
||||
variant="external"
|
||||
|
||||
-1
@@ -746,7 +746,6 @@ export function ImportTransactionsModal({
|
||||
|
||||
runImportPreview();
|
||||
// intentionally exclude runImportPreview from dependencies to avoid infinite rerenders
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [
|
||||
filetype,
|
||||
flipAmount,
|
||||
|
||||
@@ -394,7 +394,6 @@ function CustomReportInner({ report: initialReport }: CustomReportInnerProps) {
|
||||
|
||||
run();
|
||||
// omitted `conditions` and `conditionsOp` from dependencies to avoid infinite loops
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [
|
||||
interval,
|
||||
dateRange,
|
||||
|
||||
@@ -350,7 +350,6 @@ export function ScheduleEditModal({ id, transaction }: ScheduleEditModalProps) {
|
||||
}
|
||||
|
||||
run();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -138,7 +138,7 @@ export function SelectedTransactionsButton({
|
||||
const canMerge = useMemo(() => {
|
||||
return Boolean(
|
||||
twoTransactions &&
|
||||
twoTransactions[0].amount === twoTransactions[1].amount,
|
||||
twoTransactions[0].amount === twoTransactions[1].amount,
|
||||
);
|
||||
}, [twoTransactions]);
|
||||
|
||||
|
||||
@@ -19,6 +19,5 @@ export function useEffectAfterMount(
|
||||
return effect();
|
||||
}
|
||||
isFirstRender.current = false;
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, deps);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ export function useQuery<Response = unknown>(
|
||||
// Memo the resulting query. We don't care if the function
|
||||
// that creates the query changes, only the resulting query.
|
||||
// Safe to ignore the eslint warning here.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const query = useMemo(makeQuery, dependencies);
|
||||
|
||||
const [data, setData] = useState<ReadonlyArray<Response> | null>(null);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable no-empty-pattern */
|
||||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
import path from 'node:path';
|
||||
|
||||
|
||||
@@ -137,7 +137,10 @@ const sidebars = {
|
||||
type: 'doc',
|
||||
id: 'budgeting/credit-cards/index',
|
||||
},
|
||||
items: ['budgeting/credit-cards/paying-in-full', 'budgeting/credit-cards/carrying-debt'],
|
||||
items: [
|
||||
'budgeting/credit-cards/paying-in-full',
|
||||
'budgeting/credit-cards/carrying-debt',
|
||||
],
|
||||
},
|
||||
'budgeting/multi-currency',
|
||||
'budgeting/joint-accounts',
|
||||
@@ -224,7 +227,7 @@ const sidebars = {
|
||||
'experimental/monthly-cleanup',
|
||||
'experimental/rule-templating',
|
||||
'experimental/pluggyai',
|
||||
'experimental/crossover-point-report'
|
||||
'experimental/crossover-point-report',
|
||||
],
|
||||
},
|
||||
'getting-started/tips-tricks',
|
||||
|
||||
+229
-261
@@ -41,38 +41,24 @@ export let objects = {
|
||||
{
|
||||
name: 'serverURL',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
The URL of your Actual Budget server.
|
||||
</span>
|
||||
),
|
||||
description: <span>The URL of your Actual Budget server.</span>,
|
||||
},
|
||||
{
|
||||
name: 'password',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
The password of your Actual Budget server.
|
||||
</span>
|
||||
),
|
||||
description: <span>The password of your Actual Budget server.</span>,
|
||||
},
|
||||
{
|
||||
name: 'dataDir',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
The directory to store locally cached budget files.
|
||||
</span>
|
||||
<span>The directory to store locally cached budget files.</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'verbose',
|
||||
type: 'boolean',
|
||||
description: (
|
||||
<span>
|
||||
Enable/disable logging from actual internals
|
||||
</span>
|
||||
),
|
||||
description: <span>Enable/disable logging from actual internals</span>,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -126,8 +112,8 @@ export let objects = {
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
If a transfer, the <code>id</code> of the corresponding transaction in the other
|
||||
account. See <a href="#transfers">transfers</a>.
|
||||
If a transfer, the <code>id</code> of the corresponding transaction in
|
||||
the other account. See <a href="#transfers">transfers</a>.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
@@ -219,190 +205,192 @@ export let objects = {
|
||||
},
|
||||
],
|
||||
|
||||
schedule : [
|
||||
{
|
||||
name: 'id',
|
||||
type: types.id
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
Not mandatory but schedule names must be unique.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'rule',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
All schedules have an associated underlying rule. Not to be supplied with a new schedule. It will be auto created. Rules can not updated to another rule. You can however edit the rule with the API above for Rule.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'next_date',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
Next occurrence of a schedule. Not to be supplied with a new schedule.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'completed',
|
||||
type: 'boolean',
|
||||
description: (
|
||||
<span>
|
||||
Not to be supplied with a new schedule.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'posts_transaction',
|
||||
type: 'boolean',
|
||||
description: (
|
||||
<span>
|
||||
Whether the schedule should auto-post transactions on your behalf. Defaults to <code>false</code>.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'payee',
|
||||
type: 'id | null',
|
||||
description: (
|
||||
<span>
|
||||
Optional; will default to <code>null</code>.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'account',
|
||||
type: 'id | null',
|
||||
description: (
|
||||
<span>
|
||||
Optional; will default to <code>null</code>.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'amount',
|
||||
type: 'number | { num1: number; num2: number }',
|
||||
description: (
|
||||
<span>
|
||||
Provide only one number, except if the amount uses a isbetween in amountOp, in this case num1 and 2 should be provided.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'amountOp',
|
||||
type: "'is' | 'isapprox' | 'isbetween'",
|
||||
description: (
|
||||
<span>
|
||||
Controls how <code>amount</code> is interpreted.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'date',
|
||||
type: 'date | RecurConfig',
|
||||
required: true,
|
||||
description: (
|
||||
<span>
|
||||
Mandatory field when creating a schedule. If the schedule is a single occurrence just supply the date. otherwise refer to RecurConfig details below.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
],
|
||||
schedule: [
|
||||
{
|
||||
name: 'id',
|
||||
type: types.id,
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>Not mandatory but schedule names must be unique.</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'rule',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
All schedules have an associated underlying rule. Not to be supplied
|
||||
with a new schedule. It will be auto created. Rules can not updated to
|
||||
another rule. You can however edit the rule with the API above for
|
||||
Rule.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'next_date',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
Next occurrence of a schedule. Not to be supplied with a new schedule.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'completed',
|
||||
type: 'boolean',
|
||||
description: <span>Not to be supplied with a new schedule.</span>,
|
||||
},
|
||||
{
|
||||
name: 'posts_transaction',
|
||||
type: 'boolean',
|
||||
description: (
|
||||
<span>
|
||||
Whether the schedule should auto-post transactions on your behalf.
|
||||
Defaults to <code>false</code>.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'payee',
|
||||
type: 'id | null',
|
||||
description: (
|
||||
<span>
|
||||
Optional; will default to <code>null</code>.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'account',
|
||||
type: 'id | null',
|
||||
description: (
|
||||
<span>
|
||||
Optional; will default to <code>null</code>.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'amount',
|
||||
type: 'number | { num1: number; num2: number }',
|
||||
description: (
|
||||
<span>
|
||||
Provide only one number, except if the amount uses a isbetween in
|
||||
amountOp, in this case num1 and 2 should be provided.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'amountOp',
|
||||
type: "'is' | 'isapprox' | 'isbetween'",
|
||||
description: (
|
||||
<span>
|
||||
Controls how <code>amount</code> is interpreted.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'date',
|
||||
type: 'date | RecurConfig',
|
||||
required: true,
|
||||
description: (
|
||||
<span>
|
||||
Mandatory field when creating a schedule. If the schedule is a single
|
||||
occurrence just supply the date. otherwise refer to RecurConfig
|
||||
details below.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
],
|
||||
|
||||
recurConfig : [
|
||||
{
|
||||
name: 'frequency',
|
||||
type: `'daily' | 'weekly' | 'monthly' | 'yearly'`,
|
||||
required: true,
|
||||
description: (
|
||||
<span>
|
||||
How often the schedule repeats.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'interval',
|
||||
type: 'number',
|
||||
description: (
|
||||
<span>
|
||||
The interval at which the recurrence happens. Defaults to <code>1</code> if omitted.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'patterns',
|
||||
type: 'RecurPattern[]',
|
||||
description: (
|
||||
<span>
|
||||
Optional patterns to control specific dates for recurrence (e.g. certain weekdays or month days).
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'skipWeekend',
|
||||
type: 'boolean',
|
||||
description: (
|
||||
<span>
|
||||
If true, skips weekends when calculating recurrence dates.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'start',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: (
|
||||
<span>
|
||||
The ISO date string indicating the start date of the recurrence.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'endMode',
|
||||
type: `'never' | 'after_n_occurrences' | 'on_date'`,
|
||||
required: true,
|
||||
description: (
|
||||
<span>
|
||||
Specifies how the recurrence ends: never ends, after a number of occurrences, or on a specific date.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'endOccurrences',
|
||||
type: 'number',
|
||||
description: (
|
||||
<span>
|
||||
Used when <code>endMode</code> is <code>'after_n_occurrences'</code>. Indicates how many times it should repeat.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'endDate',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
Used when <code>endMode</code> is <code>'on_date'</code>. The ISO date string indicating when the recurrence should end.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'weekendSolveMode',
|
||||
type: `'before' | 'after'`,
|
||||
description: (
|
||||
<span>
|
||||
If a calculated date falls on a weekend and <code>skipWeekend</code> is true, this controls whether the date moves to the <code>before</code> or <code>after</code> weekday.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
],
|
||||
recurConfig: [
|
||||
{
|
||||
name: 'frequency',
|
||||
type: `'daily' | 'weekly' | 'monthly' | 'yearly'`,
|
||||
required: true,
|
||||
description: <span>How often the schedule repeats.</span>,
|
||||
},
|
||||
{
|
||||
name: 'interval',
|
||||
type: 'number',
|
||||
description: (
|
||||
<span>
|
||||
The interval at which the recurrence happens. Defaults to{' '}
|
||||
<code>1</code> if omitted.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'patterns',
|
||||
type: 'RecurPattern[]',
|
||||
description: (
|
||||
<span>
|
||||
Optional patterns to control specific dates for recurrence (e.g.
|
||||
certain weekdays or month days).
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'skipWeekend',
|
||||
type: 'boolean',
|
||||
description: (
|
||||
<span>If true, skips weekends when calculating recurrence dates.</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'start',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: (
|
||||
<span>
|
||||
The ISO date string indicating the start date of the recurrence.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'endMode',
|
||||
type: `'never' | 'after_n_occurrences' | 'on_date'`,
|
||||
required: true,
|
||||
description: (
|
||||
<span>
|
||||
Specifies how the recurrence ends: never ends, after a number of
|
||||
occurrences, or on a specific date.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'endOccurrences',
|
||||
type: 'number',
|
||||
description: (
|
||||
<span>
|
||||
Used when <code>endMode</code> is <code>'after_n_occurrences'</code>.
|
||||
Indicates how many times it should repeat.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'endDate',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
Used when <code>endMode</code> is <code>'on_date'</code>. The ISO date
|
||||
string indicating when the recurrence should end.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'weekendSolveMode',
|
||||
type: `'before' | 'after'`,
|
||||
description: (
|
||||
<span>
|
||||
If a calculated date falls on a weekend and <code>skipWeekend</code>{' '}
|
||||
is true, this controls whether the date moves to the{' '}
|
||||
<code>before</code> or <code>after</code> weekday.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
],
|
||||
|
||||
payee: [
|
||||
{ name: 'id', type: types.id },
|
||||
@@ -429,23 +417,24 @@ recurConfig : [
|
||||
rule: [
|
||||
{ name: 'id', type: types.id },
|
||||
{
|
||||
name: 'stage',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: (
|
||||
<span>
|
||||
Must be one of <code>pre</code>, <code>default</code>, or <code>post</code>.
|
||||
</span>
|
||||
),
|
||||
name: 'stage',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: (
|
||||
<span>
|
||||
Must be one of <code>pre</code>, <code>default</code>, or{' '}
|
||||
<code>post</code>.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'conditionsOp',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
Must be one of <code>and</code> or <code>or</code>.
|
||||
</span>
|
||||
),
|
||||
name: 'conditionsOp',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
Must be one of <code>and</code> or <code>or</code>.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{ name: 'conditions', type: 'ConditionOrAction[]' },
|
||||
{ name: 'actions', type: 'ConditionOrAction[]' },
|
||||
@@ -455,23 +444,24 @@ recurConfig : [
|
||||
{ name: 'id', type: types.id },
|
||||
{ name: 'payee_id', type: types.id, required: true },
|
||||
{
|
||||
name: 'stage',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: (
|
||||
<span>
|
||||
Must be one of <code>pre</code>, <code>default</code>, or <code>post</code>.
|
||||
</span>
|
||||
),
|
||||
name: 'stage',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: (
|
||||
<span>
|
||||
Must be one of <code>pre</code>, <code>default</code>, or{' '}
|
||||
<code>post</code>.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'conditionsOp',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
Must be one of <code>and</code> or <code>or</code>.
|
||||
</span>
|
||||
),
|
||||
name: 'conditionsOp',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
Must be one of <code>and</code> or <code>or</code>.
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{ name: 'conditions', type: 'ConditionOrAction[]' },
|
||||
{ name: 'actions', type: 'ConditionOrAction[]' },
|
||||
@@ -482,11 +472,7 @@ recurConfig : [
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: (
|
||||
<span>
|
||||
The budget's name.
|
||||
</span>
|
||||
),
|
||||
description: <span>The budget's name.</span>,
|
||||
},
|
||||
{
|
||||
name: 'cloudFileId',
|
||||
@@ -502,48 +488,30 @@ recurConfig : [
|
||||
name: 'groupId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: (
|
||||
<span>
|
||||
The group id for the budget.
|
||||
</span>
|
||||
),
|
||||
description: <span>The group id for the budget.</span>,
|
||||
},
|
||||
{
|
||||
name: 'hasKey',
|
||||
type: 'boolean',
|
||||
required: true,
|
||||
description: (
|
||||
<span>
|
||||
If the file has an encryption key.
|
||||
</span>
|
||||
),
|
||||
description: <span>If the file has an encryption key.</span>,
|
||||
},
|
||||
{
|
||||
name: 'encryptKeyId',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
The encryption key ID for the file, if it is encrypted.
|
||||
</span>
|
||||
<span>The encryption key ID for the file, if it is encrypted.</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'state',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
Remote files have this set to "remote".
|
||||
</span>
|
||||
),
|
||||
description: <span>Remote files have this set to "remote".</span>,
|
||||
},
|
||||
{
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
description: (
|
||||
<span>
|
||||
The local budget file's local ID.
|
||||
</span>
|
||||
),
|
||||
description: <span>The local budget file's local ID.</span>,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -13,18 +13,20 @@ With budget templates there is no need to manually fill in each category each mo
|
||||
With one click you can fill in your entire budget based on the templates you have added.
|
||||
|
||||
Here are a few examples of what you can do with templates, all with a single click!
|
||||
* Budget $ 100 every month
|
||||
* Budget $ 50 every other week
|
||||
* Refill a category to $ 300 at the start of a month
|
||||
* Add all leftover funds to a savings category
|
||||
* Budget 10% of your income for savings or a tithe
|
||||
* Budget the average you spend over the last 6 months
|
||||
* Save up for a big purchase many months in the future, and dynamically figure out the budget needs
|
||||
* And much more!
|
||||
|
||||
- Budget $ 100 every month
|
||||
- Budget $ 50 every other week
|
||||
- Refill a category to $ 300 at the start of a month
|
||||
- Add all leftover funds to a savings category
|
||||
- Budget 10% of your income for savings or a tithe
|
||||
- Budget the average you spend over the last 6 months
|
||||
- Save up for a big purchase many months in the future, and dynamically figure out the budget needs
|
||||
- And much more!
|
||||
|
||||
## Using Templates
|
||||
|
||||
### How to add a template
|
||||
|
||||
Create a template by adding a note to a category and adding a line that contains `#template` or `#goal` with the appropriate syntax.
|
||||
The example below shows the most basic template syntax `#template 72.99`.
|
||||
This will budget $ 72.99 when templates are run without having to manually type in the amount.
|
||||
@@ -39,30 +41,31 @@ In the budget month menu you will see the following options:
|
||||
|
||||

|
||||
|
||||
* **Check templates** will test all `#template and #goal` lines for proper syntax.
|
||||
- **Check templates** will test all `#template and #goal` lines for proper syntax.
|
||||
|
||||
* **Apply budget template** will run all templates in categories that currently have 0 budgeted.
|
||||
This will leave any existing budget amounts intact.
|
||||
- **Apply budget template** will run all templates in categories that currently have 0 budgeted.
|
||||
This will leave any existing budget amounts intact.
|
||||
|
||||
* **Overwrite with budget template** will fill in all budget cells using the templates and ignore any already existing budget amounts.
|
||||
This is the recommended method if you are using template priorities.
|
||||
- **Overwrite with budget template** will fill in all budget cells using the templates and ignore any already existing budget amounts.
|
||||
This is the recommended method if you are using template priorities.
|
||||
|
||||
#### Apply only specific templates
|
||||
|
||||
You can also apply selections of templates if you want.
|
||||
|
||||
* **Single Category**: Use the "Apply budget template" option shown below from the budget field drop down to apply templates to just that category.
|
||||
This will overwrite any existing budgeted amount.
|
||||
- **Single Category**: Use the "Apply budget template" option shown below from the budget field drop down to apply templates to just that category.
|
||||
This will overwrite any existing budgeted amount.
|
||||
|
||||

|
||||
|
||||
* **Apply templates to a single category group**: Use the "Apply budget templates" option shown below from the category group drop down to apply all templates to categories in a specific group.
|
||||
It will apply to the month furthest to the left in your budget view if viewing multiple months.
|
||||
This will overwrite any existing budgets in the categories in the group.
|
||||
- **Apply templates to a single category group**: Use the "Apply budget templates" option shown below from the category group drop down to apply all templates to categories in a specific group.
|
||||
It will apply to the month furthest to the left in your budget view if viewing multiple months.
|
||||
This will overwrite any existing budgets in the categories in the group.
|
||||
|
||||

|
||||
|
||||
### Goal Indicators
|
||||
|
||||
After having run the templates in a given month and category, the status of a respective category goal will be indicated as a text color of the category balance.
|
||||
The image below shows an example of categories in the following states: normal (no goal set), empty (no goal set), goal met(green), goal not met(orange), and a negative balance(red).
|
||||
|
||||
@@ -71,9 +74,11 @@ The image below shows an example of categories in the following states: normal (
|
||||
This goal value is based on the maximum amount that the templates in a category request to be budgeted.
|
||||
|
||||
#### Goal Indicator Information
|
||||
|
||||
If you hover over the balance value in a templated category, a tooltip will appear with info on the status of that category with respect to its templates.
|
||||
|
||||
#### Long term goals
|
||||
|
||||
By default, the goal information displayed in the goal indicator is shown on a monthly basis. It's what fully budgeting your templates would require for **this month**. The indicator color is based on the `Budgeted` amount and whether it meets the amount requested by the category templates.
|
||||
|
||||
If you would like the goal and associated indication color to be based on the category `Balance` instead of the budgeted amount, see the [Goal Directive option](#goal-directive).
|
||||
@@ -117,25 +122,23 @@ Templates can be given a priority flag to change the order that the templates ge
|
||||
- Template application order is based on the database order, not the view order. To guarantee a specific fill order use separate priorities for each category.
|
||||
- If you have multiple `schedule` or `by` template lines in a single category, they will be forced to match the same priority level as the line run first.
|
||||
- It is recommended to use the "overwrite with budget template" option when applying templates if you use priorities.
|
||||
|
||||
- **Expected budgeted amount is 200**
|
||||
- **Expected budgeted amount is 200**
|
||||
**Expected maximum category balance is 200**
|
||||
```
|
||||
#template 300
|
||||
#template-1 150 up to 200
|
||||
```
|
||||
|
||||
- **Expected budgeted amount is 450**
|
||||
```
|
||||
#template 300
|
||||
#template-1 150 up to 200
|
||||
```
|
||||
|
||||
- **Expected budgeted amount is 450**
|
||||
**No maximum category balance exists**
|
||||
```
|
||||
#template 150 up to 500
|
||||
#template-1 300
|
||||
```
|
||||
|
||||
` #template 150 up to 500
|
||||
#template-1 300
|
||||
`
|
||||
|
||||
### Notes on all templates
|
||||
|
||||
- All templates are a single line in the category notes. Depending on your screen size, they may visually render as multiple lines. When adding a template, do not put a return (or "enter") within a single template, or the parsing will not properly handle your template.
|
||||
- All templates are a single line in the category notes. Depending on your screen size, they may visually render as multiple lines. When adding a template, do not put a return (or "enter") within a single template, or the parsing will not properly handle your template.
|
||||
- Don't add a currency symbol to your template amounts.
|
||||
- Number formats that use comma for the decimal separator are not supported (e.g., 123,45). You must use 123.45.
|
||||
- Thousands separators are not supported (e.g., 1,234). You must use 1234.
|
||||
@@ -147,6 +150,7 @@ Templates can be given a priority flag to change the order that the templates ge
|
||||
There are many types of templates you can use to tailor how categories get filled to match your personal budgeting needs.
|
||||
|
||||
### Simple Type
|
||||
|
||||
The simple template type is the most basic type of template.
|
||||
The base template will budget the amount you ask it to.
|
||||
Simple!
|
||||
@@ -155,7 +159,6 @@ This template also has a few variations making it likely the most used template
|
||||
Below is an example of how it works.
|
||||
The template budgets just what you ask, no matter how much the respective category has in its balance.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
|Syntax|Budgeted Amount|
|
||||
|---|:---:|
|
||||
|`#template 50`| $ 50 |
|
||||
@@ -164,7 +167,6 @@ There is also a useful variation of a simple template.
|
||||
This variation will put a **limit** on how much the balance of a category can be that month.
|
||||
Here are some examples of how this is used
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
|Syntax| Previous Balance | Budgeted Amount | New Balance |
|
||||
|---|:---:| :---: |:---:|
|
||||
|`#template 50 up to 100`| $ 80 | $ 20 | $ 100 |
|
||||
@@ -178,7 +180,6 @@ The last variation of the simple template is sometimes referred to as a "refill"
|
||||
With this style the template budgets whatever it takes to hit a "full" amount.
|
||||
Here is how it works:
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
|Syntax| Previous Balance | Budgeted Amount | New Balance |
|
||||
|---|:---:| :---: |:---:|
|
||||
|`#template up to 150`| $ 10 | $ 140 | $ 150 |
|
||||
@@ -190,11 +191,12 @@ This variation along with the previous variation, are probably the most used tem
|
||||
They are simple enough to use easily, but are robust enough to make budgeting much simpler.
|
||||
|
||||
**Notes**:
|
||||
|
||||
- A single category with two templates that use `up to` is not supported.
|
||||
- If any single template contains an `up to`, the whole category will be subject to that limit even if there are later templates and priorities. This excludes remainders which will run after the limit is applied.
|
||||
|
||||
|
||||
#### All Variations
|
||||
|
||||
There is more flexibility with the limit part of the template.
|
||||
By default, the limit (the "up to" part of the template) is based per month.
|
||||
You can modify the limit to be per week or per day if that matches your needs better.
|
||||
@@ -202,7 +204,6 @@ You can also modify the limit to not ever remove funds over your limit.
|
||||
This can be useful if you get refunds or reimbursements that you would like to have remain inside a category even if over your limit.
|
||||
Below is examples of these different variations of simple templates.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
|Syntax|Description|Example Application|
|
||||
|---|---|---|
|
||||
|`#template 50`|Budget 50 each month|Regular monthly bills, such as internet|
|
||||
@@ -218,7 +219,6 @@ The **By** type of template is for saving up funds _by_ a certain month.
|
||||
For example, it is January and you are trying to save for a new car by the end of the year.
|
||||
If the new car will cost $ 10,000 and you plan to buy it in December, you will use something like the following:
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
|Syntax| Budgeted Amount |
|
||||
|---|:---:|
|
||||
|`#template 10000 by 2025-12` | $ 833.33 |
|
||||
@@ -228,7 +228,6 @@ The by template is smarter than just 10000/12.
|
||||
Lets say the example is the same, but you already have $ 1,500 saved.
|
||||
In that case you get this.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
|Syntax| Previous Balance | Budgeted Amount | New Balance |
|
||||
|---|:---:| :---: |:---:|
|
||||
|`#template 10000 by 2025-12` |$ 1,500 | $ 708.33 | $ 2,208.33 |
|
||||
@@ -242,31 +241,33 @@ If you have extra funds one month and add that to your car savings, the template
|
||||
**Note**: The date must be in YYYY-MM format.
|
||||
|
||||
#### Repeated savings
|
||||
|
||||
The By template can also repeat if your savings is cyclical, such as yearly taxes or insurance.
|
||||
The repeat period can be both a number of months or number of years.
|
||||
If you need to repeat based on a number of weeks, use the Week template.
|
||||
In that case use the following variation:
|
||||
<!-- prettier-ignore -->
|
||||
|
||||
|Syntax| Budgeted Amount | Note |
|
||||
|---|:---:| --- |
|
||||
|`#template 500 by 2025-03 repeat every year` | $ 166.66 | Assuming starting in January 2025 |
|
||||
|`#template 500 by 2025-03 repeat every year` | $ 41.66 | All months after March 2025 |
|
||||
|
||||
#### By Spend
|
||||
|
||||
The By template can be extended to allow some of the funds to be spent along the way.
|
||||
This is most commonly used for holiday savings where you will spend some of the money in the months leading up to the holiday.
|
||||
An example of this is buying Christmas gifts in November and December.
|
||||
The table below shows how this works.
|
||||
<!-- prettier-ignore -->
|
||||
|
||||
|Syntax| Budgeted Amount | Spent so far| New Balance| Note |
|
||||
|---|:---:| :---: | --- | --- |
|
||||
|`#template 500 by 2025-12 spend from 2025-11`| $ 41.66 | 0 | previous + $ 41.66| Assuming starting in January 2025, all months before December |
|
||||
|`#template 500 by 2025-12 spend from 2025-11`| $ 41.66 | $ 100 | $ 400 | Assuming the beginning of December, but have not spent anything in December yet |
|
||||
|
||||
#### Available Variations
|
||||
|
||||
Below is a table of the variations of the By template.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
|Syntax|Description|Example Application|
|
||||
|---|---|---|
|
||||
|`#template 500 by 2027-03`|Break down large, less-frequent expenses into manageable monthly expenses|Saving for a replacement car in a few years
|
||||
@@ -278,13 +279,13 @@ Below is a table of the variations of the By template.
|
||||
|`#template 500 by 2024-12 spend from 2024-03 repeat every 2 years`| |
|
||||
|
||||
### Periodic Type
|
||||
|
||||
If you have bills that are due on a regular interval, such as biweekly, every 6 weeks, quarterly, or once per year, this is the template for you!
|
||||
This template is similar to the simple template, but it will be based on a defined period rather than being budgeted on a monthly basis.
|
||||
You set a period and the start date, and every period, starting from your start date, you will receive the requested budgeted amount.
|
||||
Periods can be set for any number of days, weeks, months, or years.
|
||||
See the table below for examples.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
|Syntax| Budgeted Amount | Note |
|
||||
|---|:---:| :---: |
|
||||
|`#template 10 repeat every week starting 2025-01-06` | $ 50 | When budgeting in March 2025 |
|
||||
@@ -295,14 +296,15 @@ As you can see, the template will be budgeted based on the defined period.
|
||||
|
||||
The Periodic template also supports limits the same way the simple template does.
|
||||
For example, if you budget in January with a limited template:
|
||||
<!-- prettier-ignore -->
|
||||
|
||||
|Syntax| Previous Balance | Budgeted Amount | New Balance |
|
||||
|---|:---:| :---: |:---:|
|
||||
|`#template 10 repeat every week starting 2025-01-06 up to 55` | $ 20 | $ 35 | $ 55 |
|
||||
|
||||
#### Available Variations
|
||||
|
||||
Below is a table of the variations of the Week template.
|
||||
<!-- prettier-ignore -->
|
||||
|
||||
|Syntax|Description|Example Application|
|
||||
|---|---|---|
|
||||
|`#template 10 repeat every day starting 2025-01-01` | Budget 10 per day | Budget for lunches |
|
||||
@@ -317,21 +319,22 @@ Below is a table of the variations of the Week template.
|
||||
|`#template 1500 repeat every 2 years starting 2025-01-01` | Budget 1500 in January every other year |
|
||||
|
||||
**Notes**:
|
||||
|
||||
- The starting date must be in YYYY-MM-DD format.
|
||||
- A single category with two templates that use `up to` is not supported.
|
||||
- All limit variations described in the [Simple template](#simple-type) are supported.
|
||||
- If any single template contains an `up to`, the whole category will be subject to that limit even if there are later templates and priorities.
|
||||
|
||||
|
||||
### Percent Type
|
||||
|
||||
The percent template allows you to assign a percent of your income or available funds to a certain category.
|
||||
Below are the most basic examples.
|
||||
All the examples assume the following amounts of income in the listed income categories or to budget amount:
|
||||
* Paycheck - $ 1900
|
||||
* Dividends - $ 100
|
||||
* To Budget - $ 1500
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
- Paycheck - $ 1900
|
||||
- Dividends - $ 100
|
||||
- To Budget - $ 1500
|
||||
|
||||
|Syntax| Budgeted Amount | Note |
|
||||
|---|:---:| :---: |
|
||||
|`#template 10% of all income` | $ 200 | Use the total of your income categories in the calculation |
|
||||
@@ -339,10 +342,10 @@ All the examples assume the following amounts of income in the listed income cat
|
||||
|`#template 10% of available funds` | $ 150 | Budget 10% of the current to budget funds |
|
||||
|
||||
#### Previous Flag
|
||||
|
||||
The percent template can also be pointed to the previous month's income if you are using a month ahead budgeting strategy.
|
||||
Below is an example of how to do that.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
|Syntax| Budgeted Amount | Note |
|
||||
|---|:---:| :---: |
|
||||
|`#template 10% of previous all income` | $ 200 | Use the total of your income categories from the previous month |
|
||||
@@ -351,23 +354,24 @@ Below is an example of how to do that.
|
||||
The previous option is not available when using the percent of available funds template.
|
||||
|
||||
#### Available Variations
|
||||
|
||||
Below is a table of the variations of the Percent template.
|
||||
|
||||
|Syntax|Description|Example Application|
|
||||
|---|---|---|
|
||||
|`#template 15% of all income`|Budget 15% of all income categories| Using a "pay yourself first" strategy|
|
||||
|`#template 10% of Paycheck`|Budget 10% of the "Paycheck" income category| Using a "pay yourself first" strategy, but have income categories you want to ignore|
|
||||
|`#template 15% of previous all income`|Budget 15% of all income categories using last month's income|Using a "pay yourself first" strategy in conjunction with a "month ahead" strategy |
|
||||
|`#template 10% of previous Paycheck`|Budget 10% of last month's "Paycheck" income category| Using a "pay yourself first" strategy in conjunction with a "month ahead" strategy, but have income categories you want to ignore|
|
||||
|`#template 12% of available funds`|Budget 12% of your "To Budget" funds available at the current priority level| |
|
||||
| Syntax | Description | Example Application |
|
||||
| -------------------------------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `#template 15% of all income` | Budget 15% of all income categories | Using a "pay yourself first" strategy |
|
||||
| `#template 10% of Paycheck` | Budget 10% of the "Paycheck" income category | Using a "pay yourself first" strategy, but have income categories you want to ignore |
|
||||
| `#template 15% of previous all income` | Budget 15% of all income categories using last month's income | Using a "pay yourself first" strategy in conjunction with a "month ahead" strategy |
|
||||
| `#template 10% of previous Paycheck` | Budget 10% of last month's "Paycheck" income category | Using a "pay yourself first" strategy in conjunction with a "month ahead" strategy, but have income categories you want to ignore |
|
||||
| `#template 12% of available funds` | Budget 12% of your "To Budget" funds available at the current priority level | |
|
||||
|
||||
### Schedule Type
|
||||
|
||||
The Schedule template allows you to automatically budget based on the schedules you have added to Actual.
|
||||
This includes sub-monthly, month, extra-monthly schedules.
|
||||
This is the most common template outside of the Simple template.
|
||||
Below is an example of the syntax for a $ 100 per month schedule called "Internet", and a $ 2,400 per year schedule called "Taxes".
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
|Syntax| Budgeted Amount | Note |
|
||||
|---|:---:| :---: |
|
||||
|`#template schedule Internet` | $ 100 | Budget for the "Internet" schedule |
|
||||
@@ -379,13 +383,13 @@ You can adjust the schedule in the schedule editor and the template will stay up
|
||||
**Note** The schedule name is defined in the **Schedules** editor. **Take great care to copy across these schedule names EXACTLY** or the template will not be able to find the schedule.
|
||||
|
||||
#### Full Flag
|
||||
|
||||
There is one additional option to the Schedule template, the "Full" flag.
|
||||
The "Full" flag tells the template to not build up funds over time and budget the full schedule amount in the needed month.
|
||||
This is useful for small schedules that you don't need to build up over time since the amount is small.
|
||||
This can also help make stacking Schedule templates easier to track.
|
||||
Below is an example of using the "Full" flag assuming a once per year schedule for $15 called "Simplefin" due in May.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
|Syntax| Budgeted Amount | Note |
|
||||
|---|:---:| :---: |
|
||||
|`#template schedule full Simplefin` | $ 0 | Budget in all months except May |
|
||||
@@ -397,19 +401,20 @@ Yearly expenses (e.g. insurance, property rates, etc.) increase year on year. Of
|
||||
|
||||
This feature adds percentage adjustments to templates, letting you gradually save the expected increase throughout the year. By proactively budgeting a percentage change for these yearly increases, you avoid last-minute scrambling when renewal notices arrive with higher amounts.
|
||||
|
||||
|Syntax|Description|
|
||||
|---|---|
|
||||
| `#template schedule {SCHEDULE NAME} [{increase/decrease} {number}%]` | Fund the upcoming scheduled transaction over time, increasing or decreasing the amount by the given percentage
|
||||
| Syntax | Description |
|
||||
| -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
||||
| `#template schedule {SCHEDULE NAME} [{increase/decrease} {number}%]` | Fund the upcoming scheduled transaction over time, increasing or decreasing the amount by the given percentage |
|
||||
|
||||
As an example, assuming the amount Scheduled for 'Insurance' the prior year was $1000, the below would apply.
|
||||
|
||||
| Category | Template line | Amount applied |
|
||||
|---|---|:---:|
|
||||
| Insurance | `#template schedule Insurance [increase 20%]` | $1200 |
|
||||
| Category | Template line | Amount applied |
|
||||
| --------- | --------------------------------------------- | :------------: |
|
||||
| Insurance | `#template schedule Insurance [increase 20%]` | $1200 |
|
||||
|
||||
#### Available Variations
|
||||
|
||||
Below is a table of the variations of the Schedule template.
|
||||
<!-- prettier-ignore -->
|
||||
|
||||
|Syntax|Description|Example Application|
|
||||
|---|---|---|
|
||||
|`#template schedule {SCHEDULE NAME}`|Fund upcoming scheduled transactions over time|Monthly schedules, or larger non-monthly scheduled transactions|
|
||||
@@ -417,20 +422,21 @@ Below is a table of the variations of the Schedule template.
|
||||
|`#template schedule {SCHEDULE NAME} [{increase/decrease} {number}%]`|Fund upcoming scheduled transaction over time, increasing or decreasing the amount by the given percentage|Yearly renewals where the amount changes|
|
||||
|
||||
### Average Type
|
||||
|
||||
The Average template allows you to budget the average amount spend over a number of months.
|
||||
This is the same function provided by the menu in the budget table but it can be used in a single category automatically where the menu option must be applied to the whole budget or a single category.
|
||||
The table below shows how to use the Average template.
|
||||
<!-- prettier-ignore -->
|
||||
|
||||
|Syntax|Description|Example Application|
|
||||
|---|---|---|
|
||||
|`#template average 6 months` | Budget the average amount spent over the last 6 months. Can set the number to any number > 0. Matches the existing option on the budget page but with flexible month ranges | Try to budget only what you need to spend based on the last 6 months of spending data |
|
||||
|
||||
### Copy Type
|
||||
|
||||
The Copy template will copy the budget amount from some number of months prior.
|
||||
This is useful if your spending is inconsistent per month, but cyclical over a period of months.
|
||||
The table below shows how to use the Copy template.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
|Syntax|Description|Example Application|
|
||||
|---|---|---|
|
||||
|`#template copy from 12 months ago` | Budget the same amount as was budgeted 12 months ago. Number of months is adjustable | Your power bill fluctuates throughout the year, but is about the same in equivalent months between years. |
|
||||
@@ -475,11 +481,11 @@ All of the examples below use the case of 100 leftover when the remainder pass i
|
||||
|
||||
4. Spread funds over many categories, but some have limits.
|
||||
|
||||
| Category | Template line | Amount applied |
|
||||
| --------------- | ----------------------- | -------------- |
|
||||
| Category | Template line | Amount applied |
|
||||
| --------------- | -------------------------------- | -------------- |
|
||||
| Snack Fund | `#template remainder 3 up to 40` | 40 |
|
||||
| Vacation Fund | `#template remainder` | 21.66 |
|
||||
| Investment Fund | `#template remainder 2` | 38.34 |
|
||||
| Vacation Fund | `#template remainder` | 21.66 |
|
||||
| Investment Fund | `#template remainder 2` | 38.34 |
|
||||
|
||||
Notes on using the remainder template:
|
||||
|
||||
@@ -501,6 +507,7 @@ This shifts the indication to a long-term goal you are saving up to instead of j
|
||||
A few examples have been given to illustrate this difference.
|
||||
|
||||
#### Examples
|
||||
|
||||
All examples assume that 400 was carried over from the previous month
|
||||
|
||||
**1. I'm saving for a large purchase, but I'm still determining how much I can allocate each month.**
|
||||
@@ -508,34 +515,34 @@ In this case, a balance greater than or equal to 500 will set the balance green,
|
||||
If you run the template, you get the following:
|
||||
|
||||
| Template Line(s) | Amount budgeted | Balance(color) |
|
||||
|:---|:--:|---:|
|
||||
| `#goal 500` | 0 | 400(yellow) |
|
||||
| :--------------- | :-------------: | -------------: |
|
||||
| `#goal 500` | 0 | 400(yellow) |
|
||||
|
||||
If you were able to budget 100 this month, you would then hit your goal and get a green indication.
|
||||
|
||||
| Template Line(s) | Amount budgeted | Balance(color) |
|
||||
|:---|:--:|---:|
|
||||
| `#goal 500` | 100 | 500(green) |
|
||||
| :--------------- | :-------------: | -------------: |
|
||||
| `#goal 500` | 100 | 500(green) |
|
||||
|
||||
**2. I'm saving for a purchase, but I will budget 50 a month until I reach my goal.**
|
||||
In this example, a template is used to automatically budget 50 into the category when templates are run.
|
||||
The `#goal` line will override the goal indication from the `#template` line, and only go green when a balance of 500 is reached.
|
||||
If you run templates, you get the following:
|
||||
|
||||
| Template Line(s) | Amount budgeted | Balance(indication color) |
|
||||
|:---|:---:|---:|
|
||||
| `#template 50` <br /> `#goal 500` | 50 | 450(yellow) |
|
||||
| Template Line(s) | Amount budgeted | Balance(indication color) |
|
||||
| :-------------------------------- | :-------------: | ------------------------: |
|
||||
| `#template 50` <br /> `#goal 500` | 50 | 450(yellow) |
|
||||
|
||||
If you have some extra funds after templates are run and can budget that last 50, you get the following:
|
||||
|
||||
| Template Line(s) | Amount budgeted | Balance(indication color) |
|
||||
|:---|:---:|---:|
|
||||
| `#template 50` <br /> `#goal 500` | 100 | 500(green) |
|
||||
| Template Line(s) | Amount budgeted | Balance(indication color) |
|
||||
| :-------------------------------- | :-------------: | ------------------------: |
|
||||
| `#template 50` <br /> `#goal 500` | 100 | 500(green) |
|
||||
|
||||
#### Notes on The Goal Directive
|
||||
* The `#goal` templates are run the same way as the regular `#templates`.
|
||||
* If there is a `#goal` directive in a category, the goal indicator for that category will be based on the goal, not the templates.
|
||||
* The `#goal` directive will not budget any funds, and funds budgeted by hand will not get reset by running templates.
|
||||
* A `#goal` line can be stacked with `#templates` to automatically budget the category (via the templates) but override how the category goal is indicated (the goal template).
|
||||
* There is no priority on a `#goal`.
|
||||
|
||||
- The `#goal` templates are run the same way as the regular `#templates`.
|
||||
- If there is a `#goal` directive in a category, the goal indicator for that category will be based on the goal, not the templates.
|
||||
- The `#goal` directive will not budget any funds, and funds budgeted by hand will not get reset by running templates.
|
||||
- A `#goal` line can be stacked with `#templates` to automatically budget the category (via the templates) but override how the category goal is indicated (the goal template).
|
||||
- There is no priority on a `#goal`.
|
||||
|
||||
@@ -18,7 +18,6 @@ Enable this feature alongside the **Goals** experimental feature by enabling **G
|
||||
|
||||
There are different ways to interact with the cleanup script, and a few of the examples will be given. But first, let's explore the syntax.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
### Global Source and Sinks
|
||||
Global source and sink definitions can affect the whole budget.
|
||||
|
||||
|
||||
@@ -11,9 +11,7 @@
|
||||
"clear": "docusaurus clear",
|
||||
"serve": "docusaurus serve",
|
||||
"write-translations": "docusaurus write-translations",
|
||||
"write-heading-ids": "docusaurus write-heading-ids",
|
||||
"format": "prettier --write .",
|
||||
"lint": "prettier --check ."
|
||||
"write-heading-ids": "docusaurus write-heading-ids"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "^3.9.2",
|
||||
@@ -32,8 +30,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "^3.9.2",
|
||||
"@types/react": "^19.2.5",
|
||||
"prettier": "^3.6.2"
|
||||
"@types/react": "^19.2.5"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
||||
@@ -2,5 +2,4 @@ export const captureException = function (exc: Error) {
|
||||
console.error('[Exception]', exc);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line
|
||||
export const captureBreadcrumb = function (crumb: unknown) {};
|
||||
|
||||
@@ -144,8 +144,6 @@ async function execTransactionsGrouped(
|
||||
rows = await db.all<db.DbViewTransactionInternal>(rowSql, params);
|
||||
} else {
|
||||
// TODO: phew, what a doozy. write docs why it works this way
|
||||
//
|
||||
// prettier-ignore
|
||||
const rowSql = `
|
||||
SELECT group_id, matched FROM (
|
||||
SELECT
|
||||
|
||||
@@ -121,7 +121,6 @@ export type DbSchedule = {
|
||||
tombstone: 1 | 0;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
type DbScheduleJsonPath = {
|
||||
schedule_id: DbSchedule['id'];
|
||||
payee: string;
|
||||
@@ -140,7 +139,7 @@ export type DbScheduleNextDate = {
|
||||
};
|
||||
|
||||
// This is unused in the codebase.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
|
||||
type DbPendingTransaction = {
|
||||
id: string;
|
||||
acct: number;
|
||||
|
||||
@@ -22,7 +22,8 @@ import type { ApiHandlers } from './api-handlers';
|
||||
import type { ServerHandlers } from './server-handlers';
|
||||
|
||||
export interface Handlers
|
||||
extends ServerHandlers,
|
||||
extends
|
||||
ServerHandlers,
|
||||
ApiHandlers,
|
||||
BudgetHandlers,
|
||||
DashboardHandlers,
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: Maintenance
|
||||
authors: [MatissJanis]
|
||||
---
|
||||
|
||||
Move prettier and eslint to oxc
|
||||
Reference in New Issue
Block a user