diff --git a/lnbits/extensions/watchonly/static/components/wallet-config/wallet-config.js b/lnbits/extensions/watchonly/static/components/wallet-config/wallet-config.js
index c822736d3..3bd3fbf71 100644
--- a/lnbits/extensions/watchonly/static/components/wallet-config/wallet-config.js
+++ b/lnbits/extensions/watchonly/static/components/wallet-config/wallet-config.js
@@ -41,7 +41,7 @@ async function walletConfig(path) {
}
},
created: async function () {
- await this.getConfig()
+ await this.getConfig()
}
})
}
diff --git a/lnbits/extensions/watchonly/static/components/wallet-list/wallet-list.html b/lnbits/extensions/watchonly/static/components/wallet-list/wallet-list.html
new file mode 100644
index 000000000..44055f618
--- /dev/null
+++ b/lnbits/extensions/watchonly/static/components/wallet-list/wallet-list.html
@@ -0,0 +1,189 @@
+
+
+
+
+
+ Add Wallet Account
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ col.label }}
+
+
+
+
+
+
+
+
+
+
+
+ New Receive Address
+
+
+
+
+ {{props.row.title}}
+
+
+ {{getAmmountForWallet(props.row.id)}}
+
+
+ {{props.row.type}}
+
+
+ {{props.row.id}}
+
+
+
+
+
+
+
+ New Receive Address
+
+
+ {{getAccountDescription(props.row.type)}}
+
+
+
+
+
+
Master Pubkey:
+
+
+
+
+
+
+
Last Address Index:
+
+ {{props.row.address_no}}
+ none
+
+
+
+
+
Fingerprint:
+
{{props.row.fingerprint}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add Watch-Only Account
+ Cancel
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lnbits/extensions/watchonly/static/components/wallet-list/wallet-list.js b/lnbits/extensions/watchonly/static/components/wallet-list/wallet-list.js
new file mode 100644
index 000000000..83383a716
--- /dev/null
+++ b/lnbits/extensions/watchonly/static/components/wallet-list/wallet-list.js
@@ -0,0 +1,184 @@
+async function walletList(path) {
+ const template = await loadTemplateAsync(path)
+ Vue.component('wallet-list', {
+ name: 'wallet-list',
+ template,
+
+ props: ['adminkey', 'inkey', 'sats-denominated', 'addresses'],
+ data: function () {
+ return {
+ walletAccounts: [],
+ address: {},
+ formDialog: {
+ show: false,
+ data: {}
+ },
+ filter: '',
+ walletsTable: {
+ columns: [
+ {
+ name: 'new',
+ align: 'left',
+ label: ''
+ },
+ {
+ name: 'title',
+ align: 'left',
+ label: 'Title',
+ field: 'title'
+ },
+ {
+ name: 'amount',
+ align: 'left',
+ label: 'Amount'
+ },
+ {
+ name: 'type',
+ align: 'left',
+ label: 'Type',
+ field: 'type'
+ },
+ {name: 'id', align: 'left', label: 'ID', field: 'id'}
+ ],
+ pagination: {
+ rowsPerPage: 10
+ },
+ filter: ''
+ }
+ }
+ },
+
+ methods: {
+ satBtc(val, showUnit = true) {
+ return satOrBtc(val, showUnit, this['sats_denominated'])
+ },
+
+ addWalletAccount: async function () {
+ const data = _.omit(this.formDialog.data, 'wallet')
+ await this.createWalletAccount(data)
+ },
+ createWalletAccount: async function (data) {
+ try {
+ const response = await LNbits.api.request(
+ 'POST',
+ '/watchonly/api/v1/wallet',
+ this.adminkey,
+ data
+ )
+ this.walletAccounts.push(mapWalletAccount(response.data))
+ this.formDialog.show = false
+
+ await this.refreshWalletAccounts()
+ } catch (error) {
+ LNbits.utils.notifyApiError(error)
+ }
+ },
+ deleteWalletAccount: function (walletAccountId) {
+ LNbits.utils
+ .confirmDialog(
+ 'Are you sure you want to delete this watch only wallet?'
+ )
+ .onOk(async () => {
+ try {
+ await LNbits.api.request(
+ 'DELETE',
+ '/watchonly/api/v1/wallet/' + walletAccountId,
+ this.adminkey
+ )
+ this.walletAccounts = _.reject(this.walletAccounts, function (
+ obj
+ ) {
+ return obj.id === walletAccountId
+ })
+ await this.refreshWalletAccounts()
+
+ if (
+ this.payment.changeWallet &&
+ this.payment.changeWallet.id === walletAccountId
+ ) {
+ this.payment.changeWallet = this.walletAccounts[0]
+ this.selectChangeAddress(this.payment.changeWallet)
+ }
+ await this.scanAddressWithAmount()
+ } catch (error) {
+ this.$q.notify({
+ type: 'warning',
+ message:
+ 'Error while deleting wallet account. Please try again.',
+ timeout: 10000
+ })
+ }
+ })
+ },
+
+ getWatchOnlyWallets: async function () {
+ try {
+ const {data} = await LNbits.api.request(
+ 'GET',
+ '/watchonly/api/v1/wallet',
+ this.inkey
+ )
+ return data
+ } catch (error) {
+ this.$q.notify({
+ type: 'warning',
+ message: 'Failed to fetch wallets.',
+ timeout: 10000
+ })
+ LNbits.utils.notifyApiError(error)
+ }
+ return []
+ },
+ refreshWalletAccounts: async function () {
+ const wallets = await this.getWatchOnlyWallets()
+ this.walletAccounts = wallets.map(w => mapWalletAccount(w))
+ this.$emit('accounts-update', this.walletAccounts)
+ },
+ getAmmountForWallet: function (walletId) {
+ const amount = this.addresses
+ .filter(a => a.wallet === walletId)
+ .reduce((t, a) => t + a.amount || 0, 0)
+ return this.satBtc(amount)
+ },
+ closeFormDialog: function () {
+ this.formDialog.data = {
+ is_unique: false
+ }
+ },
+ getAccountDescription: function (accountType) {
+ return getAccountDescription(accountType)
+ },
+ openGetFreshAddressDialog: async function (walletId) {
+ const {data} = await LNbits.api.request(
+ 'GET',
+ `/watchonly/api/v1/address/${walletId}`,
+ this.inkey
+ )
+ const addressData = mapAddressesData(data)
+
+ addressData.note = `Shared on ${currentDateTime()}`
+ const lastAcctiveAddress =
+ this.addresses
+ .filter(
+ a =>
+ a.wallet === addressData.wallet && !a.isChange && a.hasActivity
+ )
+ .pop() || {}
+ addressData.gapLimitExceeded =
+ !addressData.isChange &&
+ addressData.addressIndex >
+ lastAcctiveAddress.addressIndex + DEFAULT_RECEIVE_GAP_LIMIT
+
+ const wallet = this.walletAccounts.find(w => w.id === walletId) || {}
+ wallet.address_no = addressData.addressIndex
+ this.$emit('new-receive-address', addressData)
+ this.$emit('accounts-update', this.walletAccounts)
+ }
+ },
+ created: async function () {
+ if (this.inkey) {
+ await this.refreshWalletAccounts()
+ }
+ }
+ })
+}
diff --git a/lnbits/extensions/watchonly/static/js/index.js b/lnbits/extensions/watchonly/static/js/index.js
index a57d59e32..1c7425f58 100644
--- a/lnbits/extensions/watchonly/static/js/index.js
+++ b/lnbits/extensions/watchonly/static/js/index.js
@@ -2,6 +2,7 @@ const watchOnly = async () => {
Vue.component(VueQrcode.name, VueQrcode)
await walletConfig('static/components/wallet-config/wallet-config.html')
+ await walletList('static/components/wallet-list/wallet-list.html')
Vue.filter('reverse', function (value) {
// slice to make a copy of array, then reverse the copy
@@ -14,7 +15,7 @@ const watchOnly = async () => {
data: function () {
return {
DUST_LIMIT: 546,
- filter: '',
+ filter: '', // todo: remove?
scan: {
scanning: false,
@@ -32,7 +33,7 @@ const watchOnly = async () => {
receive_gap_limit: 20,
change_gap_limit: 5
},
- DEFAULT_RECEIVE_GAP_LIMIT: 20,
+
show: false
},
@@ -63,17 +64,14 @@ const watchOnly = async () => {
psbtSent: false
},
- formDialog: {
- show: false,
- data: {}
- },
-
qrCodeDialog: {
show: false,
data: null
},
...tables,
- ...tableData
+ ...tableData,
+
+ walletAccounts: []
}
},
@@ -81,74 +79,6 @@ const watchOnly = async () => {
//################### CONFIG ###################
//################### WALLETS ###################
- getWalletName: function (walletId) {
- const wallet = this.walletAccounts.find(wl => wl.id === walletId)
- return wallet ? wallet.title : 'unknown'
- },
- addWalletAccount: async function () {
- const wallet = this.g.user.wallets[0]
- const data = _.omit(this.formDialog.data, 'wallet')
- await this.createWalletAccount(wallet, data)
- },
- createWalletAccount: async function (wallet, data) {
- try {
- const response = await LNbits.api.request(
- 'POST',
- '/watchonly/api/v1/wallet',
- wallet.adminkey,
- data
- )
- this.walletAccounts.push(mapWalletAccount(response.data))
- this.formDialog.show = false
-
- await this.refreshWalletAccounts()
- await this.refreshAddresses()
-
- if (!this.payment.changeWallett) {
- this.payment.changeWallet = this.walletAccounts[0]
- this.selectChangeAddress(this.payment.changeWallet)
- }
- } catch (error) {
- LNbits.utils.notifyApiError(error)
- }
- },
- deleteWalletAccount: function (walletAccountId) {
- LNbits.utils
- .confirmDialog(
- 'Are you sure you want to delete this watch only wallet?'
- )
- .onOk(async () => {
- try {
- await LNbits.api.request(
- 'DELETE',
- '/watchonly/api/v1/wallet/' + walletAccountId,
- this.g.user.wallets[0].adminkey
- )
- this.walletAccounts = _.reject(this.walletAccounts, function (
- obj
- ) {
- return obj.id === walletAccountId
- })
- await this.refreshWalletAccounts()
- await this.refreshAddresses()
- if (
- this.payment.changeWallet &&
- this.payment.changeWallet.id === walletAccountId
- ) {
- this.payment.changeWallet = this.walletAccounts[0]
- this.selectChangeAddress(this.payment.changeWallet)
- }
- await this.scanAddressWithAmount()
- } catch (error) {
- this.$q.notify({
- type: 'warning',
- message:
- 'Error while deleting wallet account. Please try again.',
- timeout: 10000
- })
- }
- })
- },
getAddressesForWallet: async function (walletId) {
try {
const {data} = await LNbits.api.request(
@@ -167,41 +97,17 @@ const watchOnly = async () => {
}
return []
},
- getWatchOnlyWallets: async function () {
- try {
- const {data} = await LNbits.api.request(
- 'GET',
- '/watchonly/api/v1/wallet',
- this.g.user.wallets[0].inkey
- )
- return data
- } catch (error) {
- this.$q.notify({
- type: 'warning',
- message: 'Failed to fetch wallets.',
- timeout: 10000
- })
- LNbits.utils.notifyApiError(error)
- }
- return []
+ getWalletName: function (walletId) {
+ const wallet = this.walletAccounts.find(wl => wl.id === walletId)
+ return wallet ? wallet.title : 'unknown'
},
- refreshWalletAccounts: async function () {
- const wallets = await this.getWatchOnlyWallets()
- this.walletAccounts = wallets.map(w => mapWalletAccount(w))
- },
- getAmmountForWallet: function (walletId) {
- const amount = this.addresses.data
- .filter(a => a.wallet === walletId)
- .reduce((t, a) => t + a.amount || 0, 0)
- return this.satBtc(amount)
- },
-
//################### ADDRESSES ###################
refreshAddresses: async function () {
- const wallets = await this.getWatchOnlyWallets()
+ // const wallets = await this.getWatchOnlyWallets() todo: revisit
+ // const wallets =
this.addresses.data = []
- for (const {id, type} of wallets) {
+ for (const {id, type} of this.walletAccounts) {
const newAddresses = await this.getAddressesForWallet(id)
const uniqueAddresses = newAddresses.filter(
newAddr =>
@@ -218,8 +124,7 @@ const watchOnly = async () => {
a.gapLimitExceeded =
!a.isChange &&
a.addressIndex >
- lastAcctiveAddress.addressIndex +
- this.config.DEFAULT_RECEIVE_GAP_LIMIT
+ lastAcctiveAddress.addressIndex + DEFAULT_RECEIVE_GAP_LIMIT
})
this.addresses.data.push(...uniqueAddresses)
}
@@ -295,33 +200,6 @@ const watchOnly = async () => {
)
return addresses
},
- openGetFreshAddressDialog: async function (walletId) {
- const {data} = await LNbits.api.request(
- 'GET',
- `/watchonly/api/v1/address/${walletId}`,
- this.g.user.wallets[0].inkey
- )
- const addressData = mapAddressesData(data)
-
- addressData.note = `Shared on ${currentDateTime()}`
- const lastAcctiveAddress =
- this.addresses.data
- .filter(
- a =>
- a.wallet === addressData.wallet && !a.isChange && a.hasActivity
- )
- .pop() || {}
- addressData.gapLimitExceeded =
- !addressData.isChange &&
- addressData.addressIndex >
- lastAcctiveAddress.addressIndex +
- this.config.DEFAULT_RECEIVE_GAP_LIMIT
-
- this.openQrCodeDialog(addressData)
- const wallet = this.walletAccounts.find(w => w.id === walletId) || {}
- wallet.address_no = addressData.addressIndex
- await this.refreshAddresses()
- },
//################### ADDRESS HISTORY ###################
addressHistoryFromTxs: function (addressData, txs) {
@@ -1158,11 +1036,7 @@ const watchOnly = async () => {
},
//################### OTHER ###################
- closeFormDialog: function () {
- this.formDialog.data = {
- is_unique: false
- }
- },
+
openQrCodeDialog: function (addressData) {
this.currentAddress = addressData
this.addresses.note = addressData.note || ''
@@ -1176,13 +1050,27 @@ const watchOnly = async () => {
satBtc(val, showUnit = true) {
return satOrBtc(val, showUnit, this.config.data.sats_denominated)
},
- getAccountDescription: function (accountType) {
- return getAccountDescription(accountType)
+ updateAccounts: async function (accounts) {
+ this.walletAccounts = accounts
+ await this.refreshAddresses()
+
+ if (this.payment.changeWallet) {
+ const changeAccount = this.walletAccounts.find(
+ w => w.id === this.payment.changeWallet.id
+ )
+ // change account deleted
+ if (!changeAccount) {
+ this.payment.changeWallet = this.walletAccounts[0]
+ this.selectChangeAddress(this.payment.changeWallet)
+ }
+ }
+ },
+ handleNewReceiveAddress: function (addressData) {
+ this.openQrCodeDialog(addressData)
}
},
created: async function () {
if (this.g.user.wallets.length) {
- await this.refreshWalletAccounts()
await this.refreshAddresses()
await this.scanAddressWithAmount()
}
diff --git a/lnbits/extensions/watchonly/static/js/tables.js b/lnbits/extensions/watchonly/static/js/tables.js
index e03a2c1ad..298760c9d 100644
--- a/lnbits/extensions/watchonly/static/js/tables.js
+++ b/lnbits/extensions/watchonly/static/js/tables.js
@@ -1,35 +1,4 @@
const tables = {
- walletsTable: {
- columns: [
- {
- name: 'new',
- align: 'left',
- label: ''
- },
- {
- name: 'title',
- align: 'left',
- label: 'Title',
- field: 'title'
- },
- {
- name: 'amount',
- align: 'left',
- label: 'Amount'
- },
- {
- name: 'type',
- align: 'left',
- label: 'Type',
- field: 'type'
- },
- {name: 'id', align: 'left', label: 'ID', field: 'id'}
- ],
- pagination: {
- rowsPerPage: 10
- },
- filter: ''
- },
utxosTable: {
columns: [
{
@@ -225,7 +194,7 @@ const tables = {
}
const tableData = {
- walletAccounts: [],
+ // walletAccounts: [], // todo: remove?
addresses: {
show: false,
data: [],
diff --git a/lnbits/extensions/watchonly/static/js/utils.js b/lnbits/extensions/watchonly/static/js/utils.js
index 0dbdee56d..d9559cf31 100644
--- a/lnbits/extensions/watchonly/static/js/utils.js
+++ b/lnbits/extensions/watchonly/static/js/utils.js
@@ -8,6 +8,8 @@ const COMMAND_WIPE = '/wipe'
const COMMAND_SEED = '/seed'
const COMMAND_RESTORE = '/restore'
+const DEFAULT_RECEIVE_GAP_LIMIT = 20
+
const blockTimeToDate = blockTime =>
blockTime ? moment(blockTime * 1000).format('LLL') : ''
@@ -158,7 +160,7 @@ function loadTemplateAsync(path) {
if (this.readyState == 4) {
if (this.status == 200) resolve(this.responseText)
- if (this.status == 404) resolve('Page not found.')
+ if (this.status == 404) resolve(`Page not found: ${path}
`)
}
}
diff --git a/lnbits/extensions/watchonly/templates/watchonly/index.html b/lnbits/extensions/watchonly/templates/watchonly/index.html
index 7e3d8500f..e80ae01eb 100644
--- a/lnbits/extensions/watchonly/templates/watchonly/index.html
+++ b/lnbits/extensions/watchonly/templates/watchonly/index.html
@@ -7,157 +7,19 @@
:config="config"
:adminkey="g.user.wallets[0].adminkey"
>
+
+
+
{% raw %}
-
-
-
-
-
- Add Wallet Account
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ col.label }}
-
-
-
-
-
-
-
-
-
-
-
- New Receive Address
-
-
-
-
- {{props.row.title}}
-
-
- {{getAmmountForWallet(props.row.id)}}
-
-
- {{props.row.type}}
-
-
- {{props.row.id}}
-
-
-
-
-
-
-
- New Receive Address
-
-
- {{getAccountDescription(props.row.type)}}
-
-
-
-
-
-
Master Pubkey:
-
-
-
-
-
-
-
Last Address Index:
-
- {{props.row.address_no}}
- none
-
-
-
-
-
Fingerprint:
-
{{props.row.fingerprint}}
-
-
-
-
-
-
-
-
-
-
+
+
@@ -1403,44 +1265,6 @@
-
-
-
-
-
-
-
-
- Add Watch-Only Account
- Cancel
-
-
-
-
-
{% raw %}
@@ -1648,5 +1472,6 @@
+
{% endblock %}