Wire admin add-account endpoint into the UI #46

Merged
padreug merged 12 commits from feat/add-account-ui into main 2026-06-18 10:03:10 +00:00
2 changed files with 103 additions and 1 deletions
Showing only changes of commit 9dd46e818c - Show all commits

feat(ui): wire admin add-account endpoint into Chart of Accounts

Surface the existing POST /api/v1/admin/accounts endpoint in the UI: a
super-user-only 'Add Account' button on the Chart of Accounts card opens
a dialog for the hierarchical account name + optional description, posts
with the wallet admin key (require_super_user), then reloads accounts.
Client-side prefix validation mirrors the server's _VALID_ACCOUNT_PREFIXES.
No currency input — an Open directive does not require currency constraints.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Padreug 2026-06-15 20:31:42 +02:00

View file

@ -69,6 +69,12 @@ window.app = Vue.createApp({
userWalletId: '', userWalletId: '',
loading: false loading: false
}, },
addAccountDialog: {
show: false,
name: '',
description: '',
loading: false
},
receivableDialog: { receivableDialog: {
show: false, show: false,
selectedUser: '', selectedUser: '',
@ -566,6 +572,45 @@ window.app = Vue.createApp({
this.syncingAccounts = false this.syncingAccounts = false
} }
}, },
showAddAccountDialog() {
this.addAccountDialog.name = ''
this.addAccountDialog.description = ''
this.addAccountDialog.show = true
},
async submitAddAccount() {
const name = (this.addAccountDialog.name || '').trim()
const validPrefixes = ['Assets:', 'Liabilities:', 'Equity:', 'Income:', 'Expenses:']
if (!validPrefixes.some(p => name.startsWith(p))) {
this.$q.notify({
type: 'warning',
message: `Account name must start with one of: ${validPrefixes.join(', ')}`
})
return
}
this.addAccountDialog.loading = true
try {
const {data} = await LNbits.api.request(
'POST',
'/libra/api/v1/admin/accounts',
this.g.user.wallets[0].adminkey,
{
name,
description: this.addAccountDialog.description || null
}
)
this.$q.notify({
type: 'positive',
message: `Account ${data.account_name} created` +
(data.synced_to_libra_db ? '' : ' (sync pending)')
})
this.addAccountDialog.show = false
await this.loadAccounts()
} catch (error) {
LNbits.utils.notifyApiError(error)
} finally {
this.addAccountDialog.loading = false
}
},
showSettingsDialog() { showSettingsDialog() {
this.settingsDialog.libraWalletId = this.settings?.libra_wallet_id || '' this.settingsDialog.libraWalletId = this.settings?.libra_wallet_id || ''
this.settingsDialog.favaUrl = this.settings?.fava_url || 'http://localhost:3333' this.settingsDialog.favaUrl = this.settings?.fava_url || 'http://localhost:3333'

View file

@ -857,7 +857,20 @@
<!-- Chart of Accounts --> <!-- Chart of Accounts -->
<q-card> <q-card>
<q-card-section> <q-card-section>
<h6 class="q-my-none q-mb-md">Chart of Accounts</h6> <div class="row items-center q-mb-md">
<h6 class="q-my-none">Chart of Accounts</h6>
<q-space></q-space>
<q-btn
v-if="isSuperUser"
unelevated
dense
size="sm"
color="primary"
icon="add"
label="Add Account"
@click="showAddAccountDialog"
></q-btn>
</div>
<q-list dense v-if="accounts.length > 0"> <q-list dense v-if="accounts.length > 0">
<q-item v-for="account in accounts" :key="account.id"> <q-item v-for="account in accounts" :key="account.id">
<q-item-section> <q-item-section>
@ -1232,6 +1245,50 @@
</q-card> </q-card>
</q-dialog> </q-dialog>
<!-- Add Account Dialog -->
<q-dialog v-model="addAccountDialog.show" position="top">
<q-card v-if="addAccountDialog.show" class="q-pa-lg q-pt-xl lnbits__dialog-card">
<q-form @submit="submitAddAccount" class="q-gutter-md">
<div class="text-h6 q-mb-md">Add Account</div>
<q-input
filled
dense
v-model.trim="addAccountDialog.name"
label="Account Name *"
placeholder="e.g., Expenses:Services:Domain"
hint="Full hierarchical name. Must start with Assets:, Liabilities:, Equity:, Income: or Expenses:"
></q-input>
<q-input
filled
dense
v-model.trim="addAccountDialog.description"
label="Description"
placeholder="Optional notes about this account"
></q-input>
<div class="text-caption text-grey">
Creates an Open directive in the Beancount ledger and syncs it into Libra
so permissions can be granted. Per-user accounts are managed automatically.
</div>
<div class="row q-mt-lg">
<q-btn
unelevated
color="primary"
type="submit"
:loading="addAccountDialog.loading"
:disable="!addAccountDialog.name"
>
Create Account
</q-btn>
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Cancel</q-btn>
</div>
</q-form>
</q-card>
</q-dialog>
<!-- Receivable Dialog --> <!-- Receivable Dialog -->
<q-dialog v-model="receivableDialog.show" position="top"> <q-dialog v-model="receivableDialog.show" position="top">
<q-card v-if="receivableDialog.show" class="q-pa-lg q-pt-xl lnbits__dialog-card"> <q-card v-if="receivableDialog.show" class="q-pa-lg q-pt-xl lnbits__dialog-card">