Browse Source

refactor: `/wallet` tweaks

fee_issues
Eneko Illarramendi 5 years ago
parent
commit
649cc888ab
  1. 14
      lnbits/core/static/js/wallet.js
  2. 4
      lnbits/core/templates/core/index.html
  3. 54
      lnbits/core/templates/core/wallet.html
  4. 2
      lnbits/core/views/api.py
  5. 44
      lnbits/static/js/base.js
  6. 25
      lnbits/static/js/components.js
  7. 2
      lnbits/static/vendor/quasar@1.9.12/quasar.ie.polyfills.umd.min.js
  8. 1
      lnbits/static/vendor/quasar@1.9.12/quasar.min.css
  9. 806
      lnbits/static/vendor/quasar@1.9.12/quasar.umd.js
  10. 6
      lnbits/static/vendor/quasar@1.9.12/quasar.umd.min.js
  11. 1
      lnbits/static/vendor/quasar@1.9.7/quasar.min.css
  12. 6
      lnbits/static/vendor/quasar@1.9.7/quasar.umd.min.js
  13. 16
      lnbits/static/vendor/vuex@3.1.3/vuex.js
  14. 6
      lnbits/static/vendor/vuex@3.1.3/vuex.min.js
  15. 12
      lnbits/templates/base.html

14
lnbits/core/static/js/wallet.js

@ -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 () {

4
lnbits/core/templates/core/index.html

@ -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>

54
lnbits/core/templates/core/wallet.html

@ -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" dense expand-separator label="Pay an invoice (outgoing)">
<q-card>
<q-card-section>
<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" expand-separator label="Get an invoice">
<q-expansion-item group="api" dense expand-separator label="Check an invoice (incoming or outgoing)"
class="q-mb-md">
<q-card>
<q-card-section>
This whole wallet will be deleted, the funds will be <strong>UNRECOVERABLE</strong>.
<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>

2
lnbits/core/views/api.py

@ -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():

44
lnbits/static/js/base.js

@ -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
});
}
}
}
};

25
lnbits/static/js/components.js

@ -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);
}

2
lnbits/static/vendor/quasar@1.9.7/quasar.ie.polyfills.umd.min.js → lnbits/static/vendor/quasar@1.9.12/quasar.ie.polyfills.umd.min.js

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

1
lnbits/static/vendor/quasar@1.9.12/quasar.min.css

File diff suppressed because one or more lines are too long

806
lnbits/static/vendor/quasar@1.9.7/quasar.umd.js → lnbits/static/vendor/quasar@1.9.12/quasar.umd.js

File diff suppressed because it is too large

6
lnbits/static/vendor/quasar@1.9.12/quasar.umd.min.js

File diff suppressed because one or more lines are too long

1
lnbits/static/vendor/quasar@1.9.7/quasar.min.css

File diff suppressed because one or more lines are too long

6
lnbits/static/vendor/quasar@1.9.7/quasar.umd.min.js

File diff suppressed because one or more lines are too long

16
lnbits/static/vendor/vuex@3.1.2/vuex.js → lnbits/static/vendor/vuex@3.1.3/vuex.js

@ -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,

6
lnbits/static/vendor/vuex@3.1.2/vuex.min.js → lnbits/static/vendor/vuex@3.1.3/vuex.min.js

File diff suppressed because one or more lines are too long

12
lnbits/templates/base.html

@ -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 %}

Loading…
Cancel
Save