Render account trees with separate lines per account

This commit is contained in:
2026-09-27 11:58:35 +02:00
parent 59ebe538cd
commit 4a1b029863
14 changed files with 743 additions and 140 deletions
+206 -1
View File
@@ -13,9 +13,29 @@ const accountsReport = {
{
title: null,
rows: [
{
account: "assets",
label: "Assets",
depth: 0,
root: true,
amounts: [
{ commodity: "EUR", quantity: "1000.0", display: "1000.00 EUR" },
],
},
{
account: "assets:bank",
label: "Bank",
depth: 1,
root: false,
amounts: [
{ commodity: "EUR", quantity: "1000.0", display: "1000.00 EUR" },
],
},
{
account: "assets:bank:checking",
label: "Checking",
depth: 2,
root: false,
amounts: [
{ commodity: "EUR", quantity: "1000.0", display: "1000.00 EUR" },
],
@@ -52,6 +72,92 @@ const equityReport = {
meta: { hledger_version: "1.52.1" },
};
const balanceSheetReport = {
report_type: "balance_sheet",
period: { begin: null, end: null },
sections: [
{
title: "Assets",
rows: [
{
account: "assets:bank",
label: "Bank",
depth: 0,
root: false,
amounts: [
{ commodity: "EUR", quantity: "1000.0", display: "1000.00 EUR" },
],
},
{
account: "assets:bank:checking",
label: "Checking",
depth: 1,
root: false,
amounts: [
{ commodity: "EUR", quantity: "1000.0", display: "1000.00 EUR" },
],
},
],
total: [{ commodity: "EUR", quantity: "1000.0", display: "1000.00 EUR" }],
},
{
title: "Liabilities",
rows: [],
total: [{ commodity: "EUR", quantity: "0.0", display: "0.00 EUR" }],
},
],
net: [{ commodity: "EUR", quantity: "1000.0", display: "1000.00 EUR" }],
meta: { hledger_version: "1.52.1" },
};
const incomeStatementReport = {
report_type: "income_statement",
period: { begin: null, end: null },
sections: [
{
title: "Revenues",
rows: [
{
account: "revenues:donations",
label: "Donations",
depth: 0,
root: false,
amounts: [
{ commodity: "EUR", quantity: "50.0", display: "50.00 EUR" },
],
},
],
total: [{ commodity: "EUR", quantity: "50.0", display: "50.00 EUR" }],
},
{
title: "Expenses",
rows: [
{
account: "expenses:hosting",
label: "Hosting",
depth: 0,
root: false,
amounts: [
{ commodity: "EUR", quantity: "20.5", display: "20.50 EUR" },
],
},
{
account: "expenses:hosting:server",
label: "Server",
depth: 1,
root: false,
amounts: [
{ commodity: "EUR", quantity: "20.5", display: "20.50 EUR" },
],
},
],
total: [{ commodity: "EUR", quantity: "20.5", display: "20.50 EUR" }],
},
],
net: [{ commodity: "EUR", quantity: "29.5", display: "29.50 EUR" }],
meta: { hledger_version: "1.52.1" },
};
acceptance("Hledger plugin", function (needs) {
needs.settings({ hledger_enabled: true });
@@ -68,6 +174,12 @@ acceptance("Hledger plugin", function (needs) {
server.get(`/hledger/topics/${TOPIC_ID}/reports/equity`, () =>
helper.response(equityReport)
);
server.get(`/hledger/topics/${TOPIC_ID}/reports/balance_sheet`, () =>
helper.response(balanceSheetReport)
);
server.get(`/hledger/topics/${TOPIC_ID}/reports/income_statement`, () =>
helper.response(incomeStatementReport)
);
});
test("renders the dashboard in place of the journal", async function (assert) {
@@ -87,8 +199,54 @@ acceptance("Hledger plugin", function (needs) {
.dom(".hledger-dashboard__toolbar .btn:nth-of-type(4)")
.hasText("Equity");
assert.dom(".hledger-dashboard__table").includesText("Total");
assert.dom(".hledger-dashboard__table").includesText("assets:bank");
assert.dom(".hledger-dashboard__table").includesText("Assets");
assert.dom(".hledger-dashboard__table").includesText("Bank");
assert.dom(".hledger-dashboard__table").includesText("Checking");
assert.dom(".hledger-dashboard__table").includesText("1000.00 EUR");
assert.dom(".hledger-dashboard__account.--depth-1").hasText("Bank");
assert.dom(".hledger-dashboard__account.--depth-2").hasText("Checking");
assert
.dom('.hledger-dashboard__account[title="assets:bank"]')
.hasText("Bank");
const rootAccount = document.querySelector(
".hledger-dashboard__account.--depth-0"
);
const childAccount = document.querySelector(
".hledger-dashboard__account.--depth-1"
);
const grandchildAccount = document.querySelector(
".hledger-dashboard__account.--depth-2"
);
const amountCell = rootAccount
.closest("tr")
.querySelector(".hledger-dashboard__amount");
const paddingStart = (element) =>
parseFloat(
getComputedStyle(element).getPropertyValue("padding-inline-start")
);
assert.true(
paddingStart(childAccount) > paddingStart(rootAccount),
"indents child accounts"
);
assert.true(
paddingStart(grandchildAccount) > paddingStart(childAccount),
"indents grandchild accounts"
);
assert.true(
["end", "right"].includes(getComputedStyle(amountCell).textAlign),
"aligns amounts to the end"
);
assert.true(
parseInt(
getComputedStyle(
document.querySelector(".hledger-dashboard__account.--root")
).fontWeight,
10
) >= 700,
"bolds root accounts"
);
});
test("switches to the equity distribution", async function (assert) {
@@ -99,4 +257,51 @@ acceptance("Hledger plugin", function (needs) {
assert.dom(".hledger-dashboard__table").includesText("alice");
assert.dom(".hledger-dashboard__table").includesText("60.00%");
});
test("renders the balance sheet and income statement as trees", async function (assert) {
await visit("/t/-/45");
await click(".hledger-dashboard__toolbar .btn:nth-of-type(2)");
assert.dom(".hledger-dashboard__section-title").exists({ count: 2 });
assert
.dom('.hledger-dashboard__account[title="assets:bank"]')
.hasText("Bank");
assert
.dom('.hledger-dashboard__account[title="assets:bank:checking"]')
.hasText("Checking");
assert
.dom(".hledger-dashboard__account.--depth-0")
.hasText("Bank", "starts the tree flush under the heading");
assert.dom(".hledger-dashboard__account.--depth-1").hasText("Checking");
assert
.dom(".hledger-dashboard__account.--root")
.doesNotExist("no root rows once the heading stands in for the root");
const bank = document.querySelector(
'.hledger-dashboard__account[title="assets:bank"]'
);
const checking = document.querySelector(
'.hledger-dashboard__account[title="assets:bank:checking"]'
);
assert.true(
parseFloat(
getComputedStyle(checking).getPropertyValue("padding-inline-start")
) >
parseFloat(
getComputedStyle(bank).getPropertyValue("padding-inline-start")
),
"indents below the heading's first level"
);
await click(".hledger-dashboard__toolbar .btn:nth-of-type(3)");
assert
.dom('.hledger-dashboard__account[title="revenues:donations"]')
.hasText("Donations");
assert
.dom('.hledger-dashboard__account[title="expenses:hosting:server"]')
.hasText("Server");
});
});