refactor: /wallet tweaks

This commit is contained in:
Eneko Illarramendi 2020-04-01 22:18:46 +02:00
parent d03785558b
commit 649cc888ab
15 changed files with 628 additions and 419 deletions

View File

@ -158,12 +158,6 @@ new Vue({
return (this.payments)
? _.where(this.payments, {pending: 1}).length > 0
: false;
},
paymentsFiltered: function () {
return this.payments;
return this.payments.filter(function (obj) {
return obj.isPaid;
});
}
},
methods: {
@ -325,6 +319,14 @@ new Vue({
this.fetchPayments(true).then(function () {
dismissMsg();
});
},
exportCSV: function () {
LNbits.utils.exportCSV(this.paymentsTable.columns, this.payments);
}
},
watch: {
'payments': function () {
EventHub.$emit('update-wallet-balance', [this.w.wallet.id, this.balance]);
}
},
created: function () {

View File

@ -57,10 +57,10 @@
</q-card-section>
<q-card-actions align="right">
<q-btn flat
color="deep-purple"
color="grey"
type="a" href="https://github.com/arcbtc/lnbits" target="_blank" rel="noopener">View project in GitHub</q-btn>
<q-btn flat
color="deep-purple"
color="grey"
type="a" href="https://paywall.link/to/f4e4e" target="_blank" rel="noopener">Donate</q-btn>
</q-card-actions>
</q-card>

View File

@ -54,7 +54,7 @@
<h5 class="text-subtitle1 q-my-none">Transactions</h5>
</div>
<div class="col-auto">
<q-btn flat color="grey" onclick="exportbut()">Export to CSV</q-btn>
<q-btn flat color="grey" @click="exportCSV">Export to CSV</q-btn>
<!--<q-btn v-if="pendingPaymentsExist" dense flat round icon="update" color="grey" @click="checkPendingPayments">
<q-tooltip>Check pending</q-tooltip>
</q-btn>-->
@ -64,7 +64,7 @@
</div>
</div>
<q-table dense flat
:data="paymentsFiltered"
:data="payments"
row-key="payhash"
:columns="paymentsTable.columns"
:pagination.sync="paymentsTable.pagination">
@ -122,40 +122,44 @@
label="API info"
:content-inset-level="0.5"
>
<q-expansion-item group="api" expand-separator label="Create an invoice">
<q-expansion-item group="api" dense expand-separator label="Create an invoice (incoming)">
<q-card>
<q-card-section>
Generate an invoice:<br /><code>POST /api/v1/invoices</code
><br />Header
<code><span class="text-light-green">POST</span> /api/v1/payments</code>
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
<code
>{"Grpc-Metadata-macaroon": "<i>{{ wallet.inkey }}</i
>"}</code
><br />
Body <code>{"value": "200","memo": "beer"} </code><br />
Returns
<code>{"pay_req": string,"pay_id": string} </code><br />
*payment will not register in the wallet until the "check
invoice" endpoint is used<br /><br />
Check invoice:<br />
Check an invoice:<br /><code
>GET /api/v1/invoice/*payment_hash*</code
><br />Header
<code
>{"Grpc-Metadata-macaroon": "<i>{{ wallet.inkey }}</i
>"}</code
><br />
Returns
<code>{"PAID": "TRUE"}/{"PAID": "FALSE"} </code><br />
*if using LNTXBOT return will hang until paid<br /><br />
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
<code>{"out": false, "value": &lt;int&gt;, "memo": &lt;string&gt;}</code>
<h5 class="text-caption q-mt-sm q-mb-none">Returns 201 CREATED (application/json)</h5>
<code>{"checking_id": &lt;string&gt;, "payment_request": &lt;string&gt;}</code>
</q-card-section>
</q-card>
</q-expansion-item>
<q-expansion-item group="api" expand-separator label="Get an invoice">
<q-expansion-item group="api" dense expand-separator label="Pay an invoice (outgoing)">
<q-card>
<q-card-section>
This whole wallet will be deleted, the funds will be <strong>UNRECOVERABLE</strong>.
<code><span class="text-light-green">POST</span> /api/v1/payments</code>
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
<code>{"Grpc-Metadata-macaroon": "{{ wallet.adminkey }}"}</code>
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
<code>{"out": true, "bolt11": &lt;string&gt;}</code>
<h5 class="text-caption q-mt-sm q-mb-none">Returns 201 CREATED (application/json)</h5>
<code>{"checking_id": &lt;string&gt;}</code>
</q-card-section>
</q-card>
</q-expansion-item>
<q-expansion-item group="api" dense expand-separator label="Check an invoice (incoming or outgoing)"
class="q-mb-md">
<q-card>
<q-card-section>
<code><span class="text-light-blue">GET</span> /api/v1/payments/&lt;checking_id&gt;</code>
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
<code>{"Grpc-Metadata-macaroon": "{{ wallet.inkey }}"}</code>
<h5 class="text-caption q-mt-sm q-mb-none">Returns 200 OK (application/json)</h5>
<code>{"paid": &lt;bool&gt;}</code>
</q-card-section>
</q-card>
</q-expansion-item>

View File

@ -45,7 +45,7 @@ def api_payments_create_invoice():
return jsonify({"checking_id": checking_id, "payment_request": payment_request}), Status.CREATED
@api_check_wallet_macaroon(key_type="invoice")
@api_check_wallet_macaroon(key_type="admin")
@api_validate_post_request(required_params=["bolt11"])
def api_payments_pay_invoice():
if not isinstance(g.data["bolt11"], str) or not g.data["bolt11"].strip():

View File

@ -1,5 +1,7 @@
var LOCALE = 'en'
var EventHub = new Vue();
var LNbits = {
api: {
request: function (method, url, macaroon, data) {
@ -20,7 +22,7 @@ var LNbits = {
});
},
payInvoice: function (wallet, bolt11) {
return this.request('post', '/api/v1/payments', wallet.inkey, {
return this.request('post', '/api/v1/payments', wallet.adminkey, {
out: true,
bolt11: bolt11
});
@ -53,7 +55,7 @@ var LNbits = {
obj.wallets = obj.wallets.map(function (obj) {
return mapWallet(obj);
}).sort(function (a, b) {
return a.name > b.name;
return a.name.localeCompare(b.name);
});
return obj;
},
@ -94,6 +96,44 @@ var LNbits = {
caption: [error.response.status, ' ', error.response.statusText].join('').toUpperCase() || null,
icon: null
});
},
exportCSV: function (columns, data) {
var wrapCsvValue = function(val, formatFn) {
var formatted = formatFn !== void 0
? formatFn(val)
: val;
formatted = (formatted === void 0 || formatted === null)
? ''
: String(formatted);
formatted = formatted.split('"').join('""');
return `"${formatted}"`;
}
var content = [columns.map(function (col) {
return wrapCsvValue(col.label);
})].concat(data.map(function (row) {
return columns.map(function (col) {
return wrapCsvValue(
(typeof col.field === 'function')
? col.field(row)
: row[(col.field === void 0) ? col.name : col.field],
col.format
);
}).join(',');
})).join('\r\n');
var status = Quasar.utils.exportFile('table-export.csv', content, 'text/csv');
if (status !== true) {
Quasar.plugins.Notify.create({
message: 'Browser denied file download...',
color: 'negative',
icon: null
});
}
}
}
};

View File

@ -3,6 +3,7 @@ Vue.component('lnbits-wallet-list', {
return {
user: null,
activeWallet: null,
activeBalance: [],
showForm: false,
walletName: ''
}
@ -10,7 +11,7 @@ Vue.component('lnbits-wallet-list', {
template: `
<q-list v-if="user && user.wallets.length" dense class="lnbits-drawer__q-list">
<q-item-label header>Wallets</q-item-label>
<q-item v-for="wallet in user.wallets" :key="wallet.id"
<q-item v-for="wallet in wallets" :key="wallet.id"
clickable
:active="activeWallet && activeWallet.id == wallet.id"
tag="a" :href="wallet.url">
@ -25,7 +26,7 @@ Vue.component('lnbits-wallet-list', {
</q-item-section>
<q-item-section>
<q-item-label lines="1">{{ wallet.name }}</q-item-label>
<q-item-label caption>{{ wallet.fsat }} sat</q-item-label>
<q-item-label caption>{{ wallet.live_fsat }} sat</q-item-label>
</q-item-section>
<q-item-section side v-show="activeWallet && activeWallet.id == wallet.id">
<q-icon name="chevron_right" color="grey-5" size="md"></q-icon>
@ -41,7 +42,7 @@ Vue.component('lnbits-wallet-list', {
</q-item>
<q-item v-if="showForm">
<q-item-section>
<q-form>
<q-form @submit="createWallet">
<q-input filled dense v-model="walletName" label="Name wallet *">
<template v-slot:append>
<q-btn round dense flat icon="send" size="sm" @click="createWallet" :disable="walletName == ''"></q-btn>
@ -52,9 +53,23 @@ Vue.component('lnbits-wallet-list', {
</q-item>
</q-list>
`,
computed: {
wallets: function () {
var bal = this.activeBalance;
return this.user.wallets.map(function (obj) {
obj.live_fsat = (bal.length && bal[0] == obj.id)
? LNbits.utils.formatSat(bal[1])
: obj.fsat;
return obj;
});
}
},
methods: {
createWallet: function () {
LNbits.href.createWallet(this.walletName, this.user.id);
},
updateWalletBalance: function (payload) {
this.activeBalance = payload;
}
},
created: function () {
@ -64,6 +79,7 @@ Vue.component('lnbits-wallet-list', {
if (window.wallet) {
this.activeWallet = LNbits.map.wallet(window.wallet);
}
EventHub.$on('update-wallet-balance', this.updateWalletBalance);
}
});
@ -113,8 +129,9 @@ Vue.component('lnbits-extension-list', {
this.extensions = window.extensions.map(function (data) {
return LNbits.map.extension(data);
}).sort(function (a, b) {
return a.name > b.name;
return a.name.localeCompare(b.name);
});
if (window.user) {
this.user = LNbits.map.user(window.user);
}

View File

@ -1,5 +1,5 @@
/*!
* Quasar Framework v1.9.7
* Quasar Framework v1.9.12
* (c) 2015-present Razvan Stoenescu
* Released under the MIT License.
*/

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
/**
* vuex v3.1.2
* (c) 2019 Evan You
* vuex v3.1.3
* (c) 2020 Evan You
* @license MIT
*/
(function (global, factory) {
@ -398,7 +398,10 @@
handler(payload);
});
});
this._subscribers.forEach(function (sub) { return sub(mutation, this$1.state); });
this._subscribers
.slice() // shallow copy to prevent iterator invalidation if subscriber synchronously calls unsubscribe
.forEach(function (sub) { return sub(mutation, this$1.state); });
if (
options && options.silent
@ -429,6 +432,7 @@
try {
this._actionSubscribers
.slice() // shallow copy to prevent iterator invalidation if subscriber synchronously calls unsubscribe
.filter(function (sub) { return sub.before; })
.forEach(function (sub) { return sub.before(action, this$1.state); });
} catch (e) {
@ -797,9 +801,7 @@
}
function getNestedState (state, path) {
return path.length
? path.reduce(function (state, key) { return state[key]; }, state)
: state
return path.reduce(function (state, key) { return state[key]; }, state)
}
function unifyObjectStyle (type, payload, options) {
@ -1042,7 +1044,7 @@
var index = {
Store: Store,
install: install,
version: '3.1.2',
version: '3.1.3',
mapState: mapState,
mapMutations: mapMutations,
mapGetters: mapGetters,

File diff suppressed because one or more lines are too long

View File

@ -3,7 +3,7 @@
<html lang="en">
<head>
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Material+Icons" type="text/css">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='vendor/quasar@1.9.7/quasar.min.css') }}">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='vendor/quasar@1.9.12/quasar.min.css') }}">
{% assets 'base_css' %}
<link rel="stylesheet" type="text/css" href="{{ ASSET_URL }}">
{% endassets %}
@ -62,15 +62,15 @@
{% if DEBUG %}
<script src="{{ url_for('static', filename='vendor/vue@2.6.11/vue.js') }}"></script>
<script src="{{ url_for('static', filename='vendor/vue-router@3.1.6/vue-router.js') }}"></script>
<script src="{{ url_for('static', filename='vendor/vuex@3.1.2/vuex.js') }}"></script>
<script src="{{ url_for('static', filename='vendor/quasar@1.9.7/quasar.umd.js') }}"></script>
<script src="{{ url_for('static', filename='vendor/vuex@3.1.3/vuex.js') }}"></script>
<script src="{{ url_for('static', filename='vendor/quasar@1.9.12/quasar.umd.js') }}"></script>
{% else %}
{% assets output='__bundle__/vue.js',
'vendor/quasar@1.9.7/quasar.ie.polyfills.umd.min.js',
'vendor/quasar@1.9.12/quasar.ie.polyfills.umd.min.js',
'vendor/vue@2.6.11/vue.min.js',
'vendor/vue-router@3.1.6/vue-router.min.js',
'vendor/vuex@3.1.2/vuex.min.js',
'vendor/quasar@1.9.7/quasar.umd.min.js' %}
'vendor/vuex@3.1.3/vuex.min.js',
'vendor/quasar@1.9.12/quasar.umd.min.js' %}
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
{% endassets %}
{% endif %}