feat: add dynamic errorpage (#3602)

This commit is contained in:
dni ⚡
2025-12-02 13:33:25 +01:00
committed by GitHub
parent 89cabda123
commit eefaf3c50c
20 changed files with 143 additions and 117 deletions
+1
View File
@@ -221,6 +221,7 @@ async def index(
@generic_router.get("/")
@generic_router.get("/error")
@generic_router.get("/node/public")
@generic_router.get("/first_install", dependencies=[Depends(check_first_install)])
async def index_public(request: Request) -> HTMLResponse:
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+9
View File
@@ -454,3 +454,12 @@ video {
width: 90% !important;
}
}
.error-code {
font-size: clamp(15vh, 20vw, 30vh);
}
.error-message {
font-size: clamp(1.5rem, 3vw, 3.75rem);
font-weight: 300;
opacity: 0.4;
}
@@ -0,0 +1,53 @@
window.app.component('lnbits-error', {
template: '#lnbits-error',
mixins: [window.windowMixin],
props: ['dynamic', 'code', 'message'],
computed: {
isExtension() {
if (this.code != 403) return false
if (this.message.startsWith('Extension ')) return true
}
},
methods: {
goBack() {
window.history.back()
},
goHome() {
window.location = '/'
},
goToWallet() {
if (this.dynamic) {
this.$router.push('/wallet')
return
}
window.location = '/wallet'
},
goToExtension() {
const extension = this.message.match(/'([^']+)'/)[1]
const url = `/extensions#${extension}`
if (this.dynamic) {
this.$router.push(url)
return
}
window.location = url
},
async logOut() {
try {
await LNbits.api.logout()
window.location = '/'
} catch (e) {
LNbits.utils.notifyApiError(e)
}
}
},
async created() {
// check if we have error from error.html
if (!this.dynamic) {
if (this.code == 401) {
console.warn(`Unauthorized: ${this.errorMessage}`)
this.logOut()
return
}
}
}
})
+2
View File
@@ -9,6 +9,8 @@ const localStore = (key, defaultValue) => {
}
window.g = Vue.reactive({
errorCode: null,
errorMessage: null,
isUserAuthorized: !!Quasar.Cookies.get('is_lnbits_user_authorized'),
offline: !navigator.onLine,
hasCamera: false,
+5
View File
@@ -78,6 +78,11 @@ const routes = [
path: '/',
name: 'PageHome',
component: PageHome
},
{
path: '/error',
name: 'PageError',
component: PageError
}
]
+4
View File
@@ -0,0 +1,4 @@
window.PageError = {
template: '#page-error',
mixins: [window.windowMixin]
}
+10 -9
View File
@@ -604,16 +604,17 @@ window.PageWallet = {
this.decodeRequest()
this.parse.show = true
}
let wallet = g.user.wallets.find(w => w.id === this.$route.params.id)
if (!wallet) {
const walletId = g.lastActiveWallet || g.user.wallets[0].id
wallet = g.user.wallets.find(w => w.id === walletId)
// TODO: should show PageError(404) if wallet not found
const wallet = g.user.wallets.find(w => w.id === this.$route.params.id)
if (wallet) {
this.g.wallet = wallet
this.g.lastActiveWallet = wallet.id
this.$q.localStorage.setItem('lnbits.lastActiveWallet', wallet.id)
this.$router.replace(`/wallet/${wallet.id}`)
} else {
this.g.errorCode = 404
this.g.errorMessage = 'Wallet not found.'
this.$router.push('/error')
}
this.g.wallet = wallet
this.g.lastActiveWallet = wallet.id
this.$q.localStorage.setItem('lnbits.lastActiveWallet', wallet.id)
this.$router.replace(`/wallet/${wallet.id}`)
},
watch: {
'g.updatePaymentsHash'() {
+9
View File
@@ -197,3 +197,12 @@ video {
}
}
}
.error-code {
font-size: clamp(15vh, 20vw, 30vh);
}
.error-message {
font-size: clamp(1.5rem, calc(1.5 / 10 * 20vw), 3.75rem);
font-weight: 300;
opacity: 0.4;
}
+2
View File
@@ -42,6 +42,7 @@
"js/bolt11-decoder.js"
],
"components": [
"js/pages/error.js",
"js/pages/home.js",
"js/pages/extensions_builder.js",
"js/pages/extensions.js",
@@ -75,6 +76,7 @@
"js/components/lnbits-wallet-paylinks.js",
"js/components/lnbits-wallet-extra.js",
"js/components/lnbits-home-logos.js",
"js/components/lnbits-error.js",
"js/components/lnbits-qrcode.js",
"js/components/lnbits-qrcode-lnurl.js",
"js/components/lnbits-disclaimer.js",
+2 -1
View File
@@ -28,7 +28,8 @@ include('components/lnbits-wallet-api-docs.vue') %} {%
include('components/lnbits-wallet-share.vue') %} {%
include('components/lnbits-wallet-charts.vue') %} {%
include('components/lnbits-wallet-paylinks.vue') %} {%
include('components/lnbits-wallet-extra.vue') %}
include('components/lnbits-wallet-extra.vue') %} {%
include('components/lnbits-error.vue') %}
<template id="lnbits-manage">
<q-list v-if="g.user" dense class="lnbits-drawer__q-list">
@@ -24,7 +24,6 @@
flat
:icon="g.walletFlip ? 'view_list' : 'view_column'"
color="grey"
class=""
@click="g.walletFlip = !g.walletFlip"
>
<q-tooltip
@@ -0,0 +1,25 @@
<template id="lnbits-error">
<div class="text-center q-pa-md flex flex-center">
<div>
<div class="error-code" v-text="code"></div>
<div class="error-message" v-text="message"></div>
<div class="q-mx-auto q-mt-lg justify-center" style="width: max-content">
<q-btn
v-if="isExtension"
color="primary"
@click="goToExtension()"
label="Go To Extension"
></q-btn>
<q-btn
v-else-if="g.isUserAuthorized"
color="primary"
@click="goToWallet()"
label="Go to Wallet"
></q-btn>
<q-btn v-else color="primary" @click="goBack()" label="Go Back"></q-btn>
<span class="q-mx-md">OR</span>
<q-btn color="secondary" @click="goHome()" label="Go Home"></q-btn>
</div>
</div>
</div>
</template>
+4 -101
View File
@@ -1,102 +1,5 @@
{% extends "public.html" %} {% block page_container %}
<q-page-container>
<q-page
class="q-px-md q-py-lg content-center"
:class="{'q-px-lg': $q.screen.gt.xs}"
>
{% block page %}
<div class="text-center q-pa-md flex flex-center">
<div v-if="statusCode">
<div class="error-code" v-text="statusCode"></div>
<div class="error-message" v-text="message"></div>
<div
class="q-mx-auto q-mt-lg justify-center"
style="width: max-content"
>
<q-btn
v-if="isExtension"
color="primary"
@click="goToExtension"
label="Go To Extension"
class="q-mb-lg full-width"
></q-btn>
<br />
<q-btn color="primary" href="/" label="Go Home"></q-btn>
<span class="q-mx-md">OR</span>
<q-btn color="primary" @click="goBack" label="Go Back"></q-btn>
</div>
</div>
</div>
{% endblock %}
</q-page>
</q-page-container>
{% endblock %} {% block scripts %}
<style>
.error-code {
font-size: clamp(15vh, 20vw, 30vh);
}
.error-message {
font-size: clamp(1.5rem, calc(1.5 / 10 * 20vw), 3.75rem);
font-weight: 300;
opacity: 0.4;
}
</style>
<script>
window.app = Vue.createApp({
el: '#vue',
mixins: [window.windowMixin],
data() {
return {
err: null,
statusCode: null,
message: null
}
},
methods: {
goBack: function () {
window.history.back()
},
goHome: function () {
window.location.href = '/'
},
goToExtension() {
window.location.href = `/extensions#${this.extension}`
},
async logOut() {
try {
await LNbits.api.logout()
window.location = '/'
} catch (e) {
LNbits.utils.notifyApiError(e)
}
},
},
computed: {
isExtension() {
if (this.statusCode != 403) return false
if (this.message.startsWith('Extension ')) return true
}
},
async created() {
this.err = '{{ err }}'
const statusCode = '{{ status_code }}' || 404
this.message = String({{ message | tojson }}) || 'Page not found'
if (statusCode == 401) {
console.warn(`Unauthorized: ${this.message}`)
this.logOut()
return
}
this.statusCode = statusCode
if (this.isExtension) {
this.extension = this.message.match(/'([^']+)'/)[1]
}
}
})
</script>
{% extends "public.html" %} {% from "macros.jinja" import window_vars with
context %} {% block scripts %} {{ window_vars() }} {% endblock %} {% block
page_container %}
<lnbits-error code="{{ status_code }}" message="{{ message }}"></lnbits-error>
{% endblock %}
+2 -1
View File
@@ -3,4 +3,5 @@ include('pages/audit.vue') %} {% include('pages/wallets.vue') %} {%
include('pages/users.vue') %} {% include('pages/admin.vue') %} {%
include('pages/account.vue') %} {% include('pages/extensions_builder.vue') %} {%
include('pages/extensions.vue') %} {% include('pages/first-install.vue') %} {%
include('pages/home.vue') %} {% include('pages/wallet.vue') %}
include('pages/home.vue') %} {% include('pages/wallet.vue') %} {%
include('pages/error.vue') %}
+9
View File
@@ -0,0 +1,9 @@
<template id="page-error">
<div id="page-error">
<lnbits-error
:dynamic="true"
:code="g.errorCode"
:message="g.errorMessage"
></lnbits-error>
</div>
</template>
+1 -1
View File
@@ -1,5 +1,5 @@
<template id="page-wallet">
<div class="row q-col-gutter-md" style="margin-bottom: 6rem">
<div v-if="g.wallet" class="row q-col-gutter-md" style="margin-bottom: 6rem">
<div class="col-12 col-md-7 q-gutter-y-md wallet-wrapper">
<q-card class="wallet-card">
<q-card-section>
+2
View File
@@ -94,6 +94,7 @@
"js/bolt11-decoder.js"
],
"components": [
"js/pages/error.js",
"js/pages/home.js",
"js/pages/extensions_builder.js",
"js/pages/extensions.js",
@@ -127,6 +128,7 @@
"js/components/lnbits-wallet-paylinks.js",
"js/components/lnbits-wallet-extra.js",
"js/components/lnbits-home-logos.js",
"js/components/lnbits-error.js",
"js/components/lnbits-qrcode.js",
"js/components/lnbits-qrcode-lnurl.js",
"js/components/lnbits-disclaimer.js",