refactor: move /admin into vue component (#3466)
This commit is contained in:
parent
2fecec2623
commit
a40306f5cd
39 changed files with 1444 additions and 1235 deletions
|
|
@ -1,302 +0,0 @@
|
||||||
{% if not ajax %} {% extends "base.html" %} {% endif %} {% from "macros.jinja"
|
|
||||||
import window_vars with context %} {% block scripts %} {{ window_vars(user) }}
|
|
||||||
{% endblock %} {% block page %}
|
|
||||||
|
|
||||||
<div class="row q-col-gutter-md q-mb-md">
|
|
||||||
<div class="col-12">
|
|
||||||
<q-card>
|
|
||||||
<div class="q-pa-sm">
|
|
||||||
<div class="row items-center justify-between q-gutter-xs">
|
|
||||||
<div class="col">
|
|
||||||
<q-btn
|
|
||||||
:label="$t('save')"
|
|
||||||
color="primary"
|
|
||||||
@click="updateSettings"
|
|
||||||
:disabled="!checkChanges"
|
|
||||||
>
|
|
||||||
<q-tooltip v-if="checkChanges">
|
|
||||||
<span v-text="$t('save_tooltip')"></span>
|
|
||||||
</q-tooltip>
|
|
||||||
|
|
||||||
<q-badge
|
|
||||||
v-if="checkChanges"
|
|
||||||
color="red"
|
|
||||||
rounded
|
|
||||||
floating
|
|
||||||
style="padding: 6px; border-radius: 6px"
|
|
||||||
/>
|
|
||||||
</q-btn>
|
|
||||||
|
|
||||||
<q-btn
|
|
||||||
v-if="isSuperUser"
|
|
||||||
:label="$t('restart')"
|
|
||||||
color="primary"
|
|
||||||
@click="restartServer"
|
|
||||||
class="q-ml-md"
|
|
||||||
>
|
|
||||||
<q-tooltip v-if="needsRestart">
|
|
||||||
<span v-text="$t('restart_tooltip')"></span>
|
|
||||||
</q-tooltip>
|
|
||||||
|
|
||||||
<q-badge
|
|
||||||
v-if="needsRestart"
|
|
||||||
color="red"
|
|
||||||
rounded
|
|
||||||
floating
|
|
||||||
style="padding: 6px; border-radius: 6px"
|
|
||||||
/>
|
|
||||||
</q-btn>
|
|
||||||
|
|
||||||
<q-btn
|
|
||||||
:label="$t('download_backup')"
|
|
||||||
flat
|
|
||||||
@click="downloadBackup"
|
|
||||||
></q-btn>
|
|
||||||
|
|
||||||
<q-btn
|
|
||||||
flat
|
|
||||||
v-if="isSuperUser"
|
|
||||||
:label="$t('reset_defaults')"
|
|
||||||
color="primary"
|
|
||||||
@click="deleteSettings"
|
|
||||||
class="float-right"
|
|
||||||
>
|
|
||||||
<q-tooltip>
|
|
||||||
<span v-text="$t('reset_defaults_tooltip')"></span>
|
|
||||||
</q-tooltip>
|
|
||||||
</q-btn>
|
|
||||||
</div>
|
|
||||||
<div></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</q-card>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row q-col-gutter-md justify-center">
|
|
||||||
<div class="col q-gutter-y-md">
|
|
||||||
<q-card>
|
|
||||||
<!-- Mobile: Horizontal tabs at top -->
|
|
||||||
<q-tabs
|
|
||||||
v-if="$q.screen.lt.md"
|
|
||||||
@update:model-value="showExchangeProvidersTab"
|
|
||||||
v-model="tab"
|
|
||||||
dense
|
|
||||||
active-color="primary"
|
|
||||||
inline-label
|
|
||||||
class="text-primary"
|
|
||||||
>
|
|
||||||
<q-tab name="funding" icon="account_balance_wallet" label="Fund" />
|
|
||||||
<q-tab name="security" icon="security" label="Sec" />
|
|
||||||
<q-tab name="server" icon="settings" label="Srv" />
|
|
||||||
<q-tab name="exchange_providers" icon="swap_horiz" label="Exch" />
|
|
||||||
<q-tab name="fiat_providers" icon="account_balance" label="Fiat" />
|
|
||||||
<q-tab name="extensions" icon="extension" label="Ext" />
|
|
||||||
<q-tab name="notifications" icon="notifications" label="Not" />
|
|
||||||
<q-tab name="audit" icon="receipt_long" label="Aud" />
|
|
||||||
<q-tab name="site_customisation" icon="language" label="Site" />
|
|
||||||
<q-tab name="library" icon="image" label="Lib" />
|
|
||||||
</q-tabs>
|
|
||||||
|
|
||||||
<!-- Desktop: Vertical sidebar with splitter -->
|
|
||||||
<q-splitter v-if="$q.screen.gt.sm">
|
|
||||||
<template v-slot:before>
|
|
||||||
<q-tabs
|
|
||||||
@update:model-value="showExchangeProvidersTab"
|
|
||||||
v-model="tab"
|
|
||||||
vertical
|
|
||||||
active-color="primary"
|
|
||||||
>
|
|
||||||
<q-tab
|
|
||||||
name="funding"
|
|
||||||
icon="account_balance_wallet"
|
|
||||||
:label="$q.screen.gt.sm ? $t('funding') : null"
|
|
||||||
@update="val => tab = val.name"
|
|
||||||
><q-tooltip v-if="!$q.screen.gt.sm"
|
|
||||||
><span v-text="$t('funding')"></span></q-tooltip
|
|
||||||
></q-tab>
|
|
||||||
<q-tab
|
|
||||||
name="security"
|
|
||||||
icon="security"
|
|
||||||
:label="$q.screen.gt.sm ? $t('security') : null"
|
|
||||||
@update="val => tab = val.name"
|
|
||||||
><q-tooltip v-if="!$q.screen.gt.sm"
|
|
||||||
><span v-text="$t('security')"></span></q-tooltip
|
|
||||||
></q-tab>
|
|
||||||
<q-tab
|
|
||||||
name="server"
|
|
||||||
icon="price_change"
|
|
||||||
:label="$q.screen.gt.sm ? $t('payments') : null"
|
|
||||||
@update="val => tab = val.name"
|
|
||||||
><q-tooltip v-if="!$q.screen.gt.sm"
|
|
||||||
><span v-text="$t('payments')"></span></q-tooltip
|
|
||||||
></q-tab>
|
|
||||||
<q-tab
|
|
||||||
name="exchange_providers"
|
|
||||||
icon="show_chart"
|
|
||||||
:label="$q.screen.gt.sm ? $t('exchanges') : null"
|
|
||||||
><q-tooltip v-if="!$q.screen.gt.sm"
|
|
||||||
><span v-text="$t('exchanges')"></span></q-tooltip
|
|
||||||
></q-tab>
|
|
||||||
<q-tab
|
|
||||||
name="fiat_providers"
|
|
||||||
icon="credit_score"
|
|
||||||
:label="$q.screen.gt.sm ? $t('fiat_providers') : null"
|
|
||||||
><q-tooltip v-if="!$q.screen.gt.sm"
|
|
||||||
><span v-text="$t('fiat_providers')"></span></q-tooltip
|
|
||||||
></q-tab>
|
|
||||||
<q-tab
|
|
||||||
name="users"
|
|
||||||
icon="group"
|
|
||||||
:label="$q.screen.gt.sm ? $t('users') : null"
|
|
||||||
@update="val => tab = val.name"
|
|
||||||
><q-tooltip v-if="!$q.screen.gt.sm"
|
|
||||||
><span v-text="$t('users')"></span></q-tooltip
|
|
||||||
></q-tab>
|
|
||||||
|
|
||||||
<q-tab
|
|
||||||
name="extensions"
|
|
||||||
icon="extension"
|
|
||||||
:label="$q.screen.gt.sm ? $t('extensions') : null"
|
|
||||||
@update="val => tab = val.name"
|
|
||||||
><q-tooltip v-if="!$q.screen.gt.sm"
|
|
||||||
><span v-text="$t('extensions')"></span></q-tooltip
|
|
||||||
></q-tab>
|
|
||||||
|
|
||||||
<q-tab
|
|
||||||
name="notifications"
|
|
||||||
icon="notifications"
|
|
||||||
:label="$q.screen.gt.sm ? $t('notifications') : null"
|
|
||||||
@update="val => tab = val.name"
|
|
||||||
><q-tooltip v-if="!$q.screen.gt.sm"
|
|
||||||
><span v-text="$t('notifications')"></span></q-tooltip
|
|
||||||
></q-tab>
|
|
||||||
<q-tab
|
|
||||||
name="audit"
|
|
||||||
icon="playlist_add_check_circle"
|
|
||||||
:label="$q.screen.gt.sm ? $t('audit') : null"
|
|
||||||
@update="val => tab = val.name"
|
|
||||||
><q-tooltip v-if="!$q.screen.gt.sm"
|
|
||||||
><span v-text="$t('audit')"></span></q-tooltip
|
|
||||||
></q-tab>
|
|
||||||
<q-tab
|
|
||||||
name="library"
|
|
||||||
icon="image"
|
|
||||||
:label="$q.screen.gt.sm ? $t('library') : null"
|
|
||||||
@update="val => tab = val.name"
|
|
||||||
><q-tooltip v-if="!$q.screen.gt.sm"
|
|
||||||
><span v-text="$t('library')"></span></q-tooltip
|
|
||||||
></q-tab>
|
|
||||||
<q-tab
|
|
||||||
style="word-break: break-all"
|
|
||||||
name="site_customisation"
|
|
||||||
icon="language"
|
|
||||||
:label="$q.screen.gt.sm ? $t('site_customisation') : null"
|
|
||||||
@update="val => tab = val.name"
|
|
||||||
><q-tooltip v-if="!$q.screen.gt.sm"
|
|
||||||
><span v-text="$t('site_customisation')"></span></q-tooltip
|
|
||||||
></q-tab>
|
|
||||||
</q-tabs>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-slot:after>
|
|
||||||
<q-form name="settings_form" id="settings_form">
|
|
||||||
<q-scroll-area style="height: 100vh">
|
|
||||||
<q-tab-panels
|
|
||||||
v-model="tab"
|
|
||||||
animated
|
|
||||||
vertical
|
|
||||||
scroll
|
|
||||||
transition-prev="jump-up"
|
|
||||||
transition-next="jump-up"
|
|
||||||
>
|
|
||||||
{% include "admin/_tab_funding.html" %} {% include
|
|
||||||
"admin/_tab_users.html" %} {% include "admin/_tab_server.html"
|
|
||||||
%} {% include "admin/_tab_exchange_providers.html" %}{% include
|
|
||||||
"admin/_tab_fiat_providers.html" %} {% include
|
|
||||||
"admin/_tab_extensions.html" %} {% include
|
|
||||||
"admin/_tab_notifications.html" %} {% include
|
|
||||||
"admin/_tab_security.html" %} {% include "admin/_tab_theme.html"
|
|
||||||
%}{% include "admin/_tab_audit.html"%}{% include
|
|
||||||
"admin/_tab_library.html"%}
|
|
||||||
</q-tab-panels>
|
|
||||||
</q-scroll-area>
|
|
||||||
</q-form>
|
|
||||||
</template>
|
|
||||||
</q-splitter>
|
|
||||||
|
|
||||||
<!-- Mobile: Full-width content without sidebar -->
|
|
||||||
<q-form
|
|
||||||
v-if="$q.screen.lt.md"
|
|
||||||
name="settings_form"
|
|
||||||
id="settings_form_mobile"
|
|
||||||
>
|
|
||||||
<q-scroll-area style="height: 70vh">
|
|
||||||
<q-tab-panels
|
|
||||||
v-model="tab"
|
|
||||||
animated
|
|
||||||
vertical
|
|
||||||
scroll
|
|
||||||
transition-prev="jump-up"
|
|
||||||
transition-next="jump-up"
|
|
||||||
style="overflow-x: hidden; padding: 8px"
|
|
||||||
>
|
|
||||||
{% include "admin/_tab_funding.html" %} {% include
|
|
||||||
"admin/_tab_users.html" %} {% include "admin/_tab_server.html" %} {%
|
|
||||||
include "admin/_tab_exchange_providers.html" %}{% include
|
|
||||||
"admin/_tab_fiat_providers.html" %} {% include
|
|
||||||
"admin/_tab_extensions.html" %} {% include
|
|
||||||
"admin/_tab_notifications.html" %} {% include
|
|
||||||
"admin/_tab_security.html" %} {% include "admin/_tab_theme.html"
|
|
||||||
%}{% include "admin/_tab_audit.html"%}{% include
|
|
||||||
"admin/_tab_library.html"%}
|
|
||||||
</q-tab-panels>
|
|
||||||
</q-scroll-area>
|
|
||||||
</q-form>
|
|
||||||
</q-card>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<q-dialog v-model="exchangeData.showTickerConversion" position="top">
|
|
||||||
<q-card class="q-pa-md q-pt-md lnbits__dialog-card">
|
|
||||||
<div class="q-mb-md">
|
|
||||||
<strong v-text="$t('create_ticker_converter')"></strong>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12 q-mb-md">
|
|
||||||
<q-select
|
|
||||||
filled
|
|
||||||
dense
|
|
||||||
v-model="exchangeData.convertFromTicker"
|
|
||||||
label="From Currency"
|
|
||||||
:options="{{ currencies | safe }}"
|
|
||||||
></q-select>
|
|
||||||
</div>
|
|
||||||
<div class="col-12">
|
|
||||||
<q-input
|
|
||||||
v-model="exchangeData.convertToTicker"
|
|
||||||
dense
|
|
||||||
filled
|
|
||||||
label="New Ticker"
|
|
||||||
hint="This ticker will be used for the exchange API calls."
|
|
||||||
>
|
|
||||||
</q-input>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row q-mt-lg">
|
|
||||||
<q-btn
|
|
||||||
@click="addExchangeTickerConversion()"
|
|
||||||
label="Add Ticker Conversion"
|
|
||||||
color="primary"
|
|
||||||
></q-btn>
|
|
||||||
<q-btn
|
|
||||||
v-close-popup
|
|
||||||
flat
|
|
||||||
color="grey"
|
|
||||||
class="q-ml-auto"
|
|
||||||
v-text="$t('close')"
|
|
||||||
></q-btn>
|
|
||||||
</div>
|
|
||||||
</q-card>
|
|
||||||
</q-dialog>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@ -20,9 +20,8 @@ from lnbits.core.services.extensions import get_valid_extensions
|
||||||
from lnbits.decorators import check_admin, check_user_exists
|
from lnbits.decorators import check_admin, check_user_exists
|
||||||
from lnbits.helpers import check_callback_url, template_renderer
|
from lnbits.helpers import check_callback_url, template_renderer
|
||||||
from lnbits.settings import settings
|
from lnbits.settings import settings
|
||||||
from lnbits.wallets import get_funding_source
|
|
||||||
|
|
||||||
from ...utils.exchange_rates import allowed_currencies, currencies
|
from ...utils.exchange_rates import allowed_currencies
|
||||||
from ..crud import (
|
from ..crud import (
|
||||||
create_wallet,
|
create_wallet,
|
||||||
get_db_versions,
|
get_db_versions,
|
||||||
|
|
@ -407,32 +406,12 @@ async def manifest(request: Request, usr: str):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@generic_router.get("/admin", response_class=HTMLResponse)
|
|
||||||
async def admin_index(request: Request, user: User = Depends(check_admin)):
|
|
||||||
if not settings.lnbits_admin_ui:
|
|
||||||
raise HTTPException(status_code=HTTPStatus.NOT_FOUND)
|
|
||||||
|
|
||||||
funding_source = get_funding_source()
|
|
||||||
_, balance = await funding_source.status()
|
|
||||||
|
|
||||||
return template_renderer().TemplateResponse(
|
|
||||||
request,
|
|
||||||
"admin/index.html",
|
|
||||||
{
|
|
||||||
"user": user.json(),
|
|
||||||
"balance": balance,
|
|
||||||
"currencies": list(currencies.keys()),
|
|
||||||
"ajax": _is_ajax_request(request),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@generic_router.get("/payments", response_class=HTMLResponse)
|
@generic_router.get("/payments", response_class=HTMLResponse)
|
||||||
@generic_router.get("/wallets", response_class=HTMLResponse)
|
@generic_router.get("/wallets", response_class=HTMLResponse)
|
||||||
async def empty_index(request: Request, user: User = Depends(check_user_exists)):
|
async def index(request: Request, user: User = Depends(check_user_exists)):
|
||||||
return template_renderer().TemplateResponse(
|
return template_renderer().TemplateResponse(
|
||||||
request,
|
request,
|
||||||
"empty.html",
|
"index.html",
|
||||||
{
|
{
|
||||||
"user": user.json(),
|
"user": user.json(),
|
||||||
},
|
},
|
||||||
|
|
@ -442,10 +421,16 @@ async def empty_index(request: Request, user: User = Depends(check_user_exists))
|
||||||
@generic_router.get("/users", response_class=HTMLResponse)
|
@generic_router.get("/users", response_class=HTMLResponse)
|
||||||
@generic_router.get("/audit", response_class=HTMLResponse)
|
@generic_router.get("/audit", response_class=HTMLResponse)
|
||||||
@generic_router.get("/node", response_class=HTMLResponse)
|
@generic_router.get("/node", response_class=HTMLResponse)
|
||||||
async def empty_admin_index(request: Request, admin: User = Depends(check_admin)):
|
@generic_router.get("/admin", response_class=HTMLResponse)
|
||||||
|
async def index_admin(request: Request, admin: User = Depends(check_admin)):
|
||||||
|
if not settings.lnbits_admin_ui:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=HTTPStatus.SERVICE_UNAVAILABLE, detail="Admin UI is disabled."
|
||||||
|
)
|
||||||
|
|
||||||
return template_renderer().TemplateResponse(
|
return template_renderer().TemplateResponse(
|
||||||
request,
|
request,
|
||||||
"empty.html",
|
"index.html",
|
||||||
{
|
{
|
||||||
"user": admin.json(),
|
"user": admin.json(),
|
||||||
},
|
},
|
||||||
|
|
@ -453,8 +438,8 @@ async def empty_admin_index(request: Request, admin: User = Depends(check_admin)
|
||||||
|
|
||||||
|
|
||||||
@generic_router.get("/node/public", response_class=HTMLResponse)
|
@generic_router.get("/node/public", response_class=HTMLResponse)
|
||||||
async def empty_public(request: Request):
|
async def index_public(request: Request):
|
||||||
return template_renderer().TemplateResponse(request, "empty_public.html")
|
return template_renderer().TemplateResponse(request, "index_public.html")
|
||||||
|
|
||||||
|
|
||||||
@generic_router.get("/uuidv4/{hex_value}")
|
@generic_router.get("/uuidv4/{hex_value}")
|
||||||
|
|
|
||||||
2
lnbits/static/bundle-components.min.js
vendored
2
lnbits/static/bundle-components.min.js
vendored
File diff suppressed because one or more lines are too long
2
lnbits/static/bundle.min.js
vendored
2
lnbits/static/bundle.min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -1,696 +0,0 @@
|
||||||
window.AdminPageLogic = {
|
|
||||||
mixins: [windowMixin],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
settings: {},
|
|
||||||
logs: [],
|
|
||||||
library_images: [],
|
|
||||||
serverlogEnabled: false,
|
|
||||||
lnbits_theme_options: [
|
|
||||||
'classic',
|
|
||||||
'bitcoin',
|
|
||||||
'flamingo',
|
|
||||||
'cyber',
|
|
||||||
'freedom',
|
|
||||||
'mint',
|
|
||||||
'autumn',
|
|
||||||
'monochrome',
|
|
||||||
'salvador'
|
|
||||||
],
|
|
||||||
reactionOptions: [
|
|
||||||
'none',
|
|
||||||
'confettiBothSides',
|
|
||||||
'confettiFireworks',
|
|
||||||
'confettiStars',
|
|
||||||
'confettiTop'
|
|
||||||
],
|
|
||||||
globalBorderOptions: [
|
|
||||||
'retro-border',
|
|
||||||
'hard-border',
|
|
||||||
'neon-border',
|
|
||||||
'no-border'
|
|
||||||
],
|
|
||||||
auditData: {},
|
|
||||||
statusData: {},
|
|
||||||
statusDataTable: {
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'date',
|
|
||||||
align: 'left',
|
|
||||||
label: this.$t('date'),
|
|
||||||
field: 'date'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'message',
|
|
||||||
align: 'left',
|
|
||||||
label: this.$t('memo'),
|
|
||||||
field: 'message'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
formData: {
|
|
||||||
lnbits_exchange_rate_providers: []
|
|
||||||
},
|
|
||||||
chartReady: false,
|
|
||||||
formAddAdmin: '',
|
|
||||||
formAddUser: '',
|
|
||||||
formAddStripeUser: '',
|
|
||||||
hideInputToggle: true,
|
|
||||||
formAddExtensionsManifest: '',
|
|
||||||
nostrNotificationIdentifier: '',
|
|
||||||
emailNotificationAddress: '',
|
|
||||||
formAllowedIPs: '',
|
|
||||||
formCallbackUrlRule: '',
|
|
||||||
formBlockedIPs: '',
|
|
||||||
nostrAcceptedUrl: '',
|
|
||||||
formAddIncludePath: '',
|
|
||||||
formAddExcludePath: '',
|
|
||||||
formAddIncludeResponseCode: '',
|
|
||||||
isSuperUser: false,
|
|
||||||
wallet: {},
|
|
||||||
cancel: {},
|
|
||||||
colors: [
|
|
||||||
'primary',
|
|
||||||
'secondary',
|
|
||||||
'accent',
|
|
||||||
'positive',
|
|
||||||
'negative',
|
|
||||||
'info',
|
|
||||||
'warning',
|
|
||||||
'red',
|
|
||||||
'yellow',
|
|
||||||
'orange'
|
|
||||||
],
|
|
||||||
tab: 'funding',
|
|
||||||
needsRestart: false,
|
|
||||||
exchangesTable: {
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'name',
|
|
||||||
align: 'left',
|
|
||||||
label: 'Exchange Name',
|
|
||||||
field: 'name',
|
|
||||||
sortable: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'api_url',
|
|
||||||
align: 'left',
|
|
||||||
label: 'URL',
|
|
||||||
field: 'api_url',
|
|
||||||
sortable: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'path',
|
|
||||||
align: 'left',
|
|
||||||
label: 'JSON Path',
|
|
||||||
field: 'path',
|
|
||||||
sortable: false
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: 'exclude_to',
|
|
||||||
align: 'left',
|
|
||||||
label: 'Exclude Currencies',
|
|
||||||
field: 'exclude_to',
|
|
||||||
sortable: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'ticker_conversion',
|
|
||||||
align: 'left',
|
|
||||||
label: 'Ticker Conversion',
|
|
||||||
field: 'ticker_conversion',
|
|
||||||
sortable: false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
pagination: {
|
|
||||||
sortBy: 'name',
|
|
||||||
rowsPerPage: 100,
|
|
||||||
page: 1,
|
|
||||||
rowsNumber: 100
|
|
||||||
},
|
|
||||||
search: null,
|
|
||||||
hideEmpty: true
|
|
||||||
},
|
|
||||||
exchangeData: {
|
|
||||||
selectedProvider: null,
|
|
||||||
showTickerConversion: false,
|
|
||||||
convertFromTicker: null,
|
|
||||||
convertToTicker: null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async created() {
|
|
||||||
await this.getSettings()
|
|
||||||
await this.getAudit()
|
|
||||||
await this.getUploadedImages()
|
|
||||||
this.balance = +'{{ balance|safe }}'
|
|
||||||
const hash = window.location.hash.replace('#', '')
|
|
||||||
if (hash === 'exchange_providers') {
|
|
||||||
this.showExchangeProvidersTab(hash)
|
|
||||||
}
|
|
||||||
if (hash) {
|
|
||||||
this.tab = hash
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
lnbitsVersion() {
|
|
||||||
return LNBITS_VERSION
|
|
||||||
},
|
|
||||||
checkChanges() {
|
|
||||||
return !_.isEqual(this.settings, this.formData)
|
|
||||||
},
|
|
||||||
updateAvailable() {
|
|
||||||
return LNBITS_VERSION !== this.statusData.version
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
addAdminUser() {
|
|
||||||
let addUser = this.formAddAdmin
|
|
||||||
let admin_users = this.formData.lnbits_admin_users
|
|
||||||
if (addUser && addUser.length && !admin_users.includes(addUser)) {
|
|
||||||
this.formData.lnbits_admin_users = [...admin_users, addUser]
|
|
||||||
this.formAddAdmin = ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeAdminUser(user) {
|
|
||||||
let admin_users = this.formData.lnbits_admin_users
|
|
||||||
this.formData.lnbits_admin_users = admin_users.filter(u => u !== user)
|
|
||||||
},
|
|
||||||
addAllowedUser() {
|
|
||||||
let addUser = this.formAddUser
|
|
||||||
let allowed_users = this.formData.lnbits_allowed_users
|
|
||||||
if (addUser && addUser.length && !allowed_users.includes(addUser)) {
|
|
||||||
this.formData.lnbits_allowed_users = [...allowed_users, addUser]
|
|
||||||
this.formAddUser = ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeAllowedUser(user) {
|
|
||||||
let allowed_users = this.formData.lnbits_allowed_users
|
|
||||||
this.formData.lnbits_allowed_users = allowed_users.filter(u => u !== user)
|
|
||||||
},
|
|
||||||
addStripeAllowedUser() {
|
|
||||||
const addUser = this.formAddStripeUser || ''
|
|
||||||
if (
|
|
||||||
addUser.length &&
|
|
||||||
!this.formData.stripe_limits.allowed_users.includes(addUser)
|
|
||||||
) {
|
|
||||||
this.formData.stripe_limits.allowed_users = [
|
|
||||||
...this.formData.stripe_limits.allowed_users,
|
|
||||||
addUser
|
|
||||||
]
|
|
||||||
this.formAddStripeUser = ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeStripeAllowedUser(user) {
|
|
||||||
this.formData.stripe_limits.allowed_users =
|
|
||||||
this.formData.stripe_limits.allowed_users.filter(u => u !== user)
|
|
||||||
},
|
|
||||||
addIncludePath() {
|
|
||||||
if (!this.formAddIncludePath) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const paths = this.formData.lnbits_audit_include_paths
|
|
||||||
if (!paths.includes(this.formAddIncludePath)) {
|
|
||||||
this.formData.lnbits_audit_include_paths = [
|
|
||||||
...paths,
|
|
||||||
this.formAddIncludePath
|
|
||||||
]
|
|
||||||
}
|
|
||||||
this.formAddIncludePath = ''
|
|
||||||
},
|
|
||||||
removeIncludePath(path) {
|
|
||||||
this.formData.lnbits_audit_include_paths =
|
|
||||||
this.formData.lnbits_audit_include_paths.filter(p => p !== path)
|
|
||||||
},
|
|
||||||
addExcludePath() {
|
|
||||||
if (!this.formAddExcludePath) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const paths = this.formData.lnbits_audit_exclude_paths
|
|
||||||
if (!paths.includes(this.formAddExcludePath)) {
|
|
||||||
this.formData.lnbits_audit_exclude_paths = [
|
|
||||||
...paths,
|
|
||||||
this.formAddExcludePath
|
|
||||||
]
|
|
||||||
}
|
|
||||||
this.formAddExcludePath = ''
|
|
||||||
},
|
|
||||||
|
|
||||||
removeExcludePath(path) {
|
|
||||||
this.formData.lnbits_audit_exclude_paths =
|
|
||||||
this.formData.lnbits_audit_exclude_paths.filter(p => p !== path)
|
|
||||||
},
|
|
||||||
addIncludeResponseCode() {
|
|
||||||
if (!this.formAddIncludeResponseCode) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const codes = this.formData.lnbits_audit_http_response_codes
|
|
||||||
if (!codes.includes(this.formAddIncludeResponseCode)) {
|
|
||||||
this.formData.lnbits_audit_http_response_codes = [
|
|
||||||
...codes,
|
|
||||||
this.formAddIncludeResponseCode
|
|
||||||
]
|
|
||||||
}
|
|
||||||
this.formAddIncludeResponseCode = ''
|
|
||||||
},
|
|
||||||
removeIncludeResponseCode(code) {
|
|
||||||
this.formData.lnbits_audit_http_response_codes =
|
|
||||||
this.formData.lnbits_audit_http_response_codes.filter(c => c !== code)
|
|
||||||
},
|
|
||||||
addExtensionsManifest() {
|
|
||||||
const addManifest = this.formAddExtensionsManifest.trim()
|
|
||||||
const manifests = this.formData.lnbits_extensions_manifests
|
|
||||||
if (
|
|
||||||
addManifest &&
|
|
||||||
addManifest.length &&
|
|
||||||
!manifests.includes(addManifest)
|
|
||||||
) {
|
|
||||||
this.formData.lnbits_extensions_manifests = [...manifests, addManifest]
|
|
||||||
this.formAddExtensionsManifest = ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeExtensionsManifest(manifest) {
|
|
||||||
const manifests = this.formData.lnbits_extensions_manifests
|
|
||||||
this.formData.lnbits_extensions_manifests = manifests.filter(
|
|
||||||
m => m !== manifest
|
|
||||||
)
|
|
||||||
},
|
|
||||||
addNostrNotificationIdentifier() {
|
|
||||||
const identifer = this.nostrNotificationIdentifier.trim()
|
|
||||||
const identifiers = this.formData.lnbits_nostr_notifications_identifiers
|
|
||||||
if (identifer && identifer.length && !identifiers.includes(identifer)) {
|
|
||||||
this.formData.lnbits_nostr_notifications_identifiers = [
|
|
||||||
...identifiers,
|
|
||||||
identifer
|
|
||||||
]
|
|
||||||
this.nostrNotificationIdentifier = ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeNostrNotificationIdentifier(identifer) {
|
|
||||||
const identifiers = this.formData.lnbits_nostr_notifications_identifiers
|
|
||||||
this.formData.lnbits_nostr_notifications_identifiers = identifiers.filter(
|
|
||||||
m => m !== identifer
|
|
||||||
)
|
|
||||||
},
|
|
||||||
addEmailNotificationAddress() {
|
|
||||||
const email = this.emailNotificationAddress.trim()
|
|
||||||
const emails = this.formData.lnbits_email_notifications_to_emails
|
|
||||||
if (email && email.length && !emails.includes(email)) {
|
|
||||||
this.formData.lnbits_email_notifications_to_emails = [...emails, email]
|
|
||||||
this.emailNotificationAddress = ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeEmailNotificationAddress(email) {
|
|
||||||
const emails = this.formData.lnbits_email_notifications_to_emails
|
|
||||||
this.formData.lnbits_email_notifications_to_emails = emails.filter(
|
|
||||||
m => m !== email
|
|
||||||
)
|
|
||||||
},
|
|
||||||
hideInputsToggle() {
|
|
||||||
this.hideInputToggle = !this.hideInputToggle
|
|
||||||
},
|
|
||||||
async toggleServerLog() {
|
|
||||||
this.serverlogEnabled = !this.serverlogEnabled
|
|
||||||
if (this.serverlogEnabled) {
|
|
||||||
const wsProto = location.protocol !== 'http:' ? 'wss://' : 'ws://'
|
|
||||||
const digestHex = await LNbits.utils.digestMessage(this.g.user.id)
|
|
||||||
const localUrl =
|
|
||||||
wsProto +
|
|
||||||
document.domain +
|
|
||||||
':' +
|
|
||||||
location.port +
|
|
||||||
'/api/v1/ws/' +
|
|
||||||
digestHex
|
|
||||||
this.ws = new WebSocket(localUrl)
|
|
||||||
this.ws.addEventListener('message', async ({data}) => {
|
|
||||||
this.logs.push(data.toString())
|
|
||||||
const scrollArea = this.$refs.logScroll
|
|
||||||
if (scrollArea) {
|
|
||||||
const scrollTarget = scrollArea.getScrollTarget()
|
|
||||||
const duration = 0
|
|
||||||
scrollArea.setScrollPosition(scrollTarget.scrollHeight, duration)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.ws.close()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
addAllowedIPs() {
|
|
||||||
const allowedIPs = this.formAllowedIPs.trim()
|
|
||||||
const allowed_ips = this.formData.lnbits_allowed_ips
|
|
||||||
if (
|
|
||||||
allowedIPs &&
|
|
||||||
allowedIPs.length &&
|
|
||||||
!allowed_ips.includes(allowedIPs)
|
|
||||||
) {
|
|
||||||
this.formData.lnbits_allowed_ips = [...allowed_ips, allowedIPs]
|
|
||||||
this.formAllowedIPs = ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeAllowedIPs(allowed_ip) {
|
|
||||||
const allowed_ips = this.formData.lnbits_allowed_ips
|
|
||||||
this.formData.lnbits_allowed_ips = allowed_ips.filter(
|
|
||||||
a => a !== allowed_ip
|
|
||||||
)
|
|
||||||
},
|
|
||||||
addBlockedIPs() {
|
|
||||||
const blockedIPs = this.formBlockedIPs.trim()
|
|
||||||
const blocked_ips = this.formData.lnbits_blocked_ips
|
|
||||||
if (
|
|
||||||
blockedIPs &&
|
|
||||||
blockedIPs.length &&
|
|
||||||
!blocked_ips.includes(blockedIPs)
|
|
||||||
) {
|
|
||||||
this.formData.lnbits_blocked_ips = [...blocked_ips, blockedIPs]
|
|
||||||
this.formBlockedIPs = ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeBlockedIPs(blocked_ip) {
|
|
||||||
const blocked_ips = this.formData.lnbits_blocked_ips
|
|
||||||
this.formData.lnbits_blocked_ips = blocked_ips.filter(
|
|
||||||
b => b !== blocked_ip
|
|
||||||
)
|
|
||||||
},
|
|
||||||
addCallbackUrlRule() {
|
|
||||||
const allowedCallback = this.formCallbackUrlRule.trim()
|
|
||||||
const allowedCallbacks = this.formData.lnbits_callback_url_rules
|
|
||||||
if (
|
|
||||||
allowedCallback &&
|
|
||||||
allowedCallback.length &&
|
|
||||||
!allowedCallbacks.includes(allowedCallback)
|
|
||||||
) {
|
|
||||||
this.formData.lnbits_callback_url_rules = [
|
|
||||||
...allowedCallbacks,
|
|
||||||
allowedCallback
|
|
||||||
]
|
|
||||||
this.formCallbackUrlRule = ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeCallbackUrlRule(allowedCallback) {
|
|
||||||
const allowedCallbacks = this.formData.lnbits_callback_url_rules
|
|
||||||
this.formData.lnbits_callback_url_rules = allowedCallbacks.filter(
|
|
||||||
a => a !== allowedCallback
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
addNostrUrl() {
|
|
||||||
const url = this.nostrAcceptedUrl.trim()
|
|
||||||
this.removeNostrUrl(url)
|
|
||||||
this.formData.nostr_absolute_request_urls.push(url)
|
|
||||||
this.nostrAcceptedUrl = ''
|
|
||||||
},
|
|
||||||
removeNostrUrl(url) {
|
|
||||||
this.formData.nostr_absolute_request_urls =
|
|
||||||
this.formData.nostr_absolute_request_urls.filter(b => b !== url)
|
|
||||||
},
|
|
||||||
addExchangeProvider() {
|
|
||||||
this.formData.lnbits_exchange_rate_providers = [
|
|
||||||
{
|
|
||||||
name: '',
|
|
||||||
api_url: '',
|
|
||||||
path: '',
|
|
||||||
exclude_to: []
|
|
||||||
},
|
|
||||||
...this.formData.lnbits_exchange_rate_providers
|
|
||||||
]
|
|
||||||
},
|
|
||||||
removeExchangeProvider(provider) {
|
|
||||||
this.formData.lnbits_exchange_rate_providers =
|
|
||||||
this.formData.lnbits_exchange_rate_providers.filter(p => p !== provider)
|
|
||||||
},
|
|
||||||
removeExchangeTickerConversion(provider, ticker) {
|
|
||||||
provider.ticker_conversion = provider.ticker_conversion.filter(
|
|
||||||
t => t !== ticker
|
|
||||||
)
|
|
||||||
this.touchSettings()
|
|
||||||
},
|
|
||||||
addExchangeTickerConversion() {
|
|
||||||
if (!this.exchangeData.selectedProvider) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.exchangeData.selectedProvider.ticker_conversion.push(
|
|
||||||
`${this.exchangeData.convertFromTicker}:${this.exchangeData.convertToTicker}`
|
|
||||||
)
|
|
||||||
this.touchSettings()
|
|
||||||
this.exchangeData.showTickerConversion = false
|
|
||||||
},
|
|
||||||
showTickerConversionDialog(provider) {
|
|
||||||
this.exchangeData.convertFromTicker = null
|
|
||||||
this.exchangeData.convertToTicker = null
|
|
||||||
this.exchangeData.selectedProvider = provider
|
|
||||||
this.exchangeData.showTickerConversion = true
|
|
||||||
},
|
|
||||||
|
|
||||||
getDefaultSetting(fieldName) {
|
|
||||||
LNbits.api
|
|
||||||
.request(
|
|
||||||
'GET',
|
|
||||||
`/admin/api/v1/settings/default?field_name=${fieldName}`
|
|
||||||
)
|
|
||||||
.then(response => {
|
|
||||||
this.formData[fieldName] = response.data.default_value
|
|
||||||
})
|
|
||||||
.catch(function (error) {
|
|
||||||
LNbits.utils.notifyApiError(error)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
restartServer() {
|
|
||||||
LNbits.api
|
|
||||||
.request('GET', '/admin/api/v1/restart/')
|
|
||||||
.then(response => {
|
|
||||||
this.$q.notify({
|
|
||||||
type: 'positive',
|
|
||||||
message: 'Success! Restarted Server',
|
|
||||||
icon: null
|
|
||||||
})
|
|
||||||
this.needsRestart = false
|
|
||||||
})
|
|
||||||
.catch(LNbits.utils.notifyApiError)
|
|
||||||
},
|
|
||||||
formatDate(date) {
|
|
||||||
return moment
|
|
||||||
.utc(date * 1000)
|
|
||||||
.local()
|
|
||||||
.fromNow()
|
|
||||||
},
|
|
||||||
sendTestEmail() {
|
|
||||||
LNbits.api
|
|
||||||
.request(
|
|
||||||
'GET',
|
|
||||||
'/admin/api/v1/testemail',
|
|
||||||
this.g.user.wallets[0].adminkey
|
|
||||||
)
|
|
||||||
.then(response => {
|
|
||||||
if (response.data.status === 'error') {
|
|
||||||
throw new Error(response.data.message)
|
|
||||||
}
|
|
||||||
this.$q.notify({
|
|
||||||
message: 'Test email sent!',
|
|
||||||
color: 'positive'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
this.$q.notify({
|
|
||||||
message: error.message,
|
|
||||||
color: 'negative'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
getAudit() {
|
|
||||||
LNbits.api
|
|
||||||
.request('GET', '/admin/api/v1/audit', this.g.user.wallets[0].adminkey)
|
|
||||||
.then(response => {
|
|
||||||
this.auditData = response.data
|
|
||||||
})
|
|
||||||
.catch(LNbits.utils.notifyApiError)
|
|
||||||
},
|
|
||||||
getExchangeRateHistory() {
|
|
||||||
LNbits.api
|
|
||||||
.request('GET', '/api/v1/rate/history', this.g.user.wallets[0].inkey)
|
|
||||||
.then(response => {
|
|
||||||
this.initExchangeChart(response.data)
|
|
||||||
})
|
|
||||||
.catch(function (error) {
|
|
||||||
LNbits.utils.notifyApiError(error)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
async getSettings() {
|
|
||||||
await LNbits.api
|
|
||||||
.request(
|
|
||||||
'GET',
|
|
||||||
'/admin/api/v1/settings',
|
|
||||||
this.g.user.wallets[0].adminkey
|
|
||||||
)
|
|
||||||
.then(response => {
|
|
||||||
this.isSuperUser = response.data.is_super_user || false
|
|
||||||
this.settings = response.data
|
|
||||||
this.formData = {...this.settings}
|
|
||||||
})
|
|
||||||
.catch(LNbits.utils.notifyApiError)
|
|
||||||
},
|
|
||||||
updateSettings() {
|
|
||||||
const data = _.omit(this.formData, [
|
|
||||||
'is_super_user',
|
|
||||||
'lnbits_allowed_funding_sources',
|
|
||||||
'touch'
|
|
||||||
])
|
|
||||||
LNbits.api
|
|
||||||
.request(
|
|
||||||
'PUT',
|
|
||||||
'/admin/api/v1/settings',
|
|
||||||
this.g.user.wallets[0].adminkey,
|
|
||||||
data
|
|
||||||
)
|
|
||||||
.then(response => {
|
|
||||||
this.needsRestart =
|
|
||||||
this.settings.lnbits_backend_wallet_class !==
|
|
||||||
this.formData.lnbits_backend_wallet_class
|
|
||||||
this.settings = this.formData
|
|
||||||
this.formData = _.clone(this.settings)
|
|
||||||
Quasar.Notify.create({
|
|
||||||
type: 'positive',
|
|
||||||
message: `Success! Settings changed! ${
|
|
||||||
this.needsRestart ? 'Restart required!' : ''
|
|
||||||
}`,
|
|
||||||
icon: null
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(LNbits.utils.notifyApiError)
|
|
||||||
},
|
|
||||||
deleteSettings() {
|
|
||||||
LNbits.utils
|
|
||||||
.confirmDialog('Are you sure you want to restore settings to default?')
|
|
||||||
.onOk(() => {
|
|
||||||
LNbits.api
|
|
||||||
.request('DELETE', '/admin/api/v1/settings')
|
|
||||||
.then(response => {
|
|
||||||
Quasar.Notify.create({
|
|
||||||
type: 'positive',
|
|
||||||
message:
|
|
||||||
'Success! Restored settings to defaults. Restarting...',
|
|
||||||
icon: null
|
|
||||||
})
|
|
||||||
this.$q.localStorage.clear()
|
|
||||||
})
|
|
||||||
.catch(LNbits.utils.notifyApiError)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
onImageInput(e) {
|
|
||||||
const file = e.target.files[0]
|
|
||||||
if (file) {
|
|
||||||
this.uploadImage(file)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
uploadImage(file) {
|
|
||||||
const formData = new FormData()
|
|
||||||
formData.append('file', file)
|
|
||||||
LNbits.api
|
|
||||||
.request(
|
|
||||||
'POST',
|
|
||||||
'/admin/api/v1/images',
|
|
||||||
this.g.user.wallets[0].adminkey,
|
|
||||||
formData,
|
|
||||||
{headers: {'Content-Type': 'multipart/form-data'}}
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
this.$q.notify({
|
|
||||||
type: 'positive',
|
|
||||||
message: 'Image uploaded!',
|
|
||||||
icon: null
|
|
||||||
})
|
|
||||||
this.getUploadedImages()
|
|
||||||
})
|
|
||||||
.catch(LNbits.utils.notifyApiError)
|
|
||||||
},
|
|
||||||
getUploadedImages() {
|
|
||||||
LNbits.api
|
|
||||||
.request('GET', '/admin/api/v1/images', this.g.user.wallets[0].inkey)
|
|
||||||
.then(response => {
|
|
||||||
this.library_images = response.data.map(image => ({
|
|
||||||
...image,
|
|
||||||
url: `${window.origin}/${image.directory}/${image.filename}`
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
.catch(LNbits.utils.notifyApiError)
|
|
||||||
},
|
|
||||||
deleteImage(filename) {
|
|
||||||
LNbits.utils
|
|
||||||
.confirmDialog('Are you sure you want to delete this image?')
|
|
||||||
.onOk(() => {
|
|
||||||
LNbits.api
|
|
||||||
.request(
|
|
||||||
'DELETE',
|
|
||||||
`/admin/api/v1/images/${filename}`,
|
|
||||||
this.g.user.wallets[0].adminkey
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
this.$q.notify({
|
|
||||||
type: 'positive',
|
|
||||||
message: 'Image deleted!',
|
|
||||||
icon: null
|
|
||||||
})
|
|
||||||
this.getUploadedImages()
|
|
||||||
})
|
|
||||||
.catch(LNbits.utils.notifyApiError)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
checkFiatProvider(providerName) {
|
|
||||||
LNbits.api
|
|
||||||
.request('PUT', `/api/v1/fiat/check/${providerName}`)
|
|
||||||
.then(response => {
|
|
||||||
response
|
|
||||||
const data = response.data
|
|
||||||
Quasar.Notify.create({
|
|
||||||
type: data.success ? 'positive' : 'warning',
|
|
||||||
message: data.message,
|
|
||||||
icon: null
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(LNbits.utils.notifyApiError)
|
|
||||||
},
|
|
||||||
downloadBackup() {
|
|
||||||
window.open('/admin/api/v1/backup', '_blank')
|
|
||||||
},
|
|
||||||
showExchangeProvidersTab(tabName) {
|
|
||||||
if (tabName === 'exchange_providers') {
|
|
||||||
this.getExchangeRateHistory()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
touchSettings() {
|
|
||||||
this.formData.touch = null
|
|
||||||
},
|
|
||||||
initExchangeChart(data) {
|
|
||||||
const xValues = data.map(d =>
|
|
||||||
Quasar.date.formatDate(new Date(d.timestamp * 1000), 'HH:mm')
|
|
||||||
)
|
|
||||||
const exchanges = [
|
|
||||||
...this.formData.lnbits_exchange_rate_providers,
|
|
||||||
{name: 'LNbits'}
|
|
||||||
]
|
|
||||||
const datasets = exchanges.map(exchange => ({
|
|
||||||
label: exchange.name,
|
|
||||||
data: data.map(d => d.rates[exchange.name]),
|
|
||||||
pointStyle: true,
|
|
||||||
borderWidth: exchange.name === 'LNbits' ? 4 : 1,
|
|
||||||
tension: 0.4
|
|
||||||
}))
|
|
||||||
this.exchangeRatesChart = new Chart(
|
|
||||||
this.$refs.exchangeRatesChart.getContext('2d'),
|
|
||||||
{
|
|
||||||
type: 'line',
|
|
||||||
options: {
|
|
||||||
plugins: {
|
|
||||||
legend: {
|
|
||||||
display: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
labels: xValues,
|
|
||||||
datasets
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
66
lnbits/static/js/components/admin/lnbits-admin-audit.js
Normal file
66
lnbits/static/js/components/admin/lnbits-admin-audit.js
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
window.app.component('lnbits-admin-audit', {
|
||||||
|
props: ['form-data'],
|
||||||
|
template: '#lnbits-admin-audit',
|
||||||
|
mixins: [window.windowMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
formAddIncludePath: '',
|
||||||
|
formAddExcludePath: '',
|
||||||
|
formAddIncludeResponseCode: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
addIncludePath() {
|
||||||
|
if (this.formAddIncludePath === '') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const paths = this.formData.lnbits_audit_include_paths
|
||||||
|
if (!paths.includes(this.formAddIncludePath)) {
|
||||||
|
this.formData.lnbits_audit_include_paths = [
|
||||||
|
...paths,
|
||||||
|
this.formAddIncludePath
|
||||||
|
]
|
||||||
|
}
|
||||||
|
this.formAddIncludePath = ''
|
||||||
|
},
|
||||||
|
removeIncludePath(path) {
|
||||||
|
this.formData.lnbits_audit_include_paths =
|
||||||
|
this.formData.lnbits_audit_include_paths.filter(p => p !== path)
|
||||||
|
},
|
||||||
|
addExcludePath() {
|
||||||
|
if (this.formAddExcludePath === '') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const paths = this.formData.lnbits_audit_exclude_paths
|
||||||
|
if (!paths.includes(this.formAddExcludePath)) {
|
||||||
|
this.formData.lnbits_audit_exclude_paths = [
|
||||||
|
...paths,
|
||||||
|
this.formAddExcludePath
|
||||||
|
]
|
||||||
|
}
|
||||||
|
this.formAddExcludePath = ''
|
||||||
|
},
|
||||||
|
|
||||||
|
removeExcludePath(path) {
|
||||||
|
this.formData.lnbits_audit_exclude_paths =
|
||||||
|
this.formData.lnbits_audit_exclude_paths.filter(p => p !== path)
|
||||||
|
},
|
||||||
|
addIncludeResponseCode() {
|
||||||
|
if (this.formAddIncludeResponseCode === '') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const codes = this.formData.lnbits_audit_http_response_codes
|
||||||
|
if (!codes.includes(this.formAddIncludeResponseCode)) {
|
||||||
|
this.formData.lnbits_audit_http_response_codes = [
|
||||||
|
...codes,
|
||||||
|
this.formAddIncludeResponseCode
|
||||||
|
]
|
||||||
|
}
|
||||||
|
this.formAddIncludeResponseCode = ''
|
||||||
|
},
|
||||||
|
removeIncludeResponseCode(code) {
|
||||||
|
this.formData.lnbits_audit_http_response_codes =
|
||||||
|
this.formData.lnbits_audit_http_response_codes.filter(c => c !== code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,159 @@
|
||||||
|
window.app.component('lnbits-admin-exchange-providers', {
|
||||||
|
props: ['form-data'],
|
||||||
|
template: '#lnbits-admin-exchange-providers',
|
||||||
|
mixins: [window.windowMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
exchangeData: {
|
||||||
|
selectedProvider: null,
|
||||||
|
showTickerConversion: false,
|
||||||
|
convertFromTicker: null,
|
||||||
|
convertToTicker: null
|
||||||
|
},
|
||||||
|
exchangesTable: {
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
align: 'left',
|
||||||
|
label: 'Exchange Name',
|
||||||
|
field: 'name',
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'api_url',
|
||||||
|
align: 'left',
|
||||||
|
label: 'URL',
|
||||||
|
field: 'api_url',
|
||||||
|
sortable: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'path',
|
||||||
|
align: 'left',
|
||||||
|
label: 'JSON Path',
|
||||||
|
field: 'path',
|
||||||
|
sortable: false
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'exclude_to',
|
||||||
|
align: 'left',
|
||||||
|
label: 'Exclude Currencies',
|
||||||
|
field: 'exclude_to',
|
||||||
|
sortable: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ticker_conversion',
|
||||||
|
align: 'left',
|
||||||
|
label: 'Ticker Conversion',
|
||||||
|
field: 'ticker_conversion',
|
||||||
|
sortable: false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
pagination: {
|
||||||
|
sortBy: 'name',
|
||||||
|
rowsPerPage: 100,
|
||||||
|
page: 1,
|
||||||
|
rowsNumber: 100
|
||||||
|
},
|
||||||
|
search: null,
|
||||||
|
hideEmpty: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getExchangeRateHistory()
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
const hash = window.location.hash.replace('#', '')
|
||||||
|
if (hash === 'exchange_providers') {
|
||||||
|
this.showExchangeProvidersTab(hash)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getExchangeRateHistory() {
|
||||||
|
LNbits.api
|
||||||
|
.request('GET', '/api/v1/rate/history', this.g.user.wallets[0].inkey)
|
||||||
|
.then(response => {
|
||||||
|
this.initExchangeChart(response.data)
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
LNbits.utils.notifyApiError(error)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
showExchangeProvidersTab(tabName) {
|
||||||
|
if (tabName === 'exchange_providers') {
|
||||||
|
this.getExchangeRateHistory()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addExchangeProvider() {
|
||||||
|
this.formData.lnbits_exchange_rate_providers = [
|
||||||
|
{
|
||||||
|
name: '',
|
||||||
|
api_url: '',
|
||||||
|
path: '',
|
||||||
|
exclude_to: []
|
||||||
|
},
|
||||||
|
...this.formData.lnbits_exchange_rate_providers
|
||||||
|
]
|
||||||
|
},
|
||||||
|
removeExchangeProvider(provider) {
|
||||||
|
this.formData.lnbits_exchange_rate_providers =
|
||||||
|
this.formData.lnbits_exchange_rate_providers.filter(p => p !== provider)
|
||||||
|
},
|
||||||
|
removeExchangeTickerConversion(provider, ticker) {
|
||||||
|
provider.ticker_conversion = provider.ticker_conversion.filter(
|
||||||
|
t => t !== ticker
|
||||||
|
)
|
||||||
|
this.formData.touch = null
|
||||||
|
},
|
||||||
|
addExchangeTickerConversion() {
|
||||||
|
if (!this.exchangeData.selectedProvider) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.exchangeData.selectedProvider.ticker_conversion.push(
|
||||||
|
`${this.exchangeData.convertFromTicker}:${this.exchangeData.convertToTicker}`
|
||||||
|
)
|
||||||
|
this.formData.touch = null
|
||||||
|
this.exchangeData.showTickerConversion = false
|
||||||
|
},
|
||||||
|
showTickerConversionDialog(provider) {
|
||||||
|
this.exchangeData.convertFromTicker = null
|
||||||
|
this.exchangeData.convertToTicker = null
|
||||||
|
this.exchangeData.selectedProvider = provider
|
||||||
|
this.exchangeData.showTickerConversion = true
|
||||||
|
},
|
||||||
|
initExchangeChart(data) {
|
||||||
|
const xValues = data.map(d =>
|
||||||
|
Quasar.date.formatDate(new Date(d.timestamp * 1000), 'HH:mm')
|
||||||
|
)
|
||||||
|
const exchanges = [
|
||||||
|
...this.formData.lnbits_exchange_rate_providers,
|
||||||
|
{name: 'LNbits'}
|
||||||
|
]
|
||||||
|
const datasets = exchanges.map(exchange => ({
|
||||||
|
label: exchange.name,
|
||||||
|
data: data.map(d => d.rates[exchange.name]),
|
||||||
|
pointStyle: true,
|
||||||
|
borderWidth: exchange.name === 'LNbits' ? 4 : 1,
|
||||||
|
tension: 0.4
|
||||||
|
}))
|
||||||
|
this.exchangeRatesChart = new Chart(
|
||||||
|
this.$refs.exchangeRatesChart.getContext('2d'),
|
||||||
|
{
|
||||||
|
type: 'line',
|
||||||
|
options: {
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
display: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
labels: xValues,
|
||||||
|
datasets
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
30
lnbits/static/js/components/admin/lnbits-admin-extensions.js
Normal file
30
lnbits/static/js/components/admin/lnbits-admin-extensions.js
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
window.app.component('lnbits-admin-extensions', {
|
||||||
|
props: ['form-data'],
|
||||||
|
template: '#lnbits-admin-extensions',
|
||||||
|
mixins: [window.windowMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
formAddExtensionsManifest: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
addExtensionsManifest() {
|
||||||
|
const addManifest = this.formAddExtensionsManifest.trim()
|
||||||
|
const manifests = this.formData.lnbits_extensions_manifests
|
||||||
|
if (
|
||||||
|
addManifest &&
|
||||||
|
addManifest.length &&
|
||||||
|
!manifests.includes(addManifest)
|
||||||
|
) {
|
||||||
|
this.formData.lnbits_extensions_manifests = [...manifests, addManifest]
|
||||||
|
this.formAddExtensionsManifest = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeExtensionsManifest(manifest) {
|
||||||
|
const manifests = this.formData.lnbits_extensions_manifests
|
||||||
|
this.formData.lnbits_extensions_manifests = manifests.filter(
|
||||||
|
m => m !== manifest
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
window.app.component('lnbits-admin-fiat-providers', {
|
||||||
|
props: ['form-data'],
|
||||||
|
template: '#lnbits-admin-fiat-providers',
|
||||||
|
mixins: [window.windowMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
formAddStripeUser: '',
|
||||||
|
hideInputToggle: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
addStripeAllowedUser() {
|
||||||
|
const addUser = this.formAddStripeUser || ''
|
||||||
|
if (
|
||||||
|
addUser.length &&
|
||||||
|
!this.formData.stripe_limits.allowed_users.includes(addUser)
|
||||||
|
) {
|
||||||
|
this.formData.stripe_limits.allowed_users = [
|
||||||
|
...this.formData.stripe_limits.allowed_users,
|
||||||
|
addUser
|
||||||
|
]
|
||||||
|
this.formAddStripeUser = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeStripeAllowedUser(user) {
|
||||||
|
this.formData.stripe_limits.allowed_users =
|
||||||
|
this.formData.stripe_limits.allowed_users.filter(u => u !== user)
|
||||||
|
},
|
||||||
|
checkFiatProvider(providerName) {
|
||||||
|
LNbits.api
|
||||||
|
.request('PUT', `/api/v1/fiat/check/${providerName}`)
|
||||||
|
.then(response => {
|
||||||
|
response
|
||||||
|
const data = response.data
|
||||||
|
Quasar.Notify.create({
|
||||||
|
type: data.success ? 'positive' : 'warning',
|
||||||
|
message: data.message,
|
||||||
|
icon: null
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(LNbits.utils.notifyApiError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
window.app.component('lnbits-funding-sources', {
|
window.app.component('lnbits-admin-funding-sources', {
|
||||||
template: '#lnbits-funding-sources',
|
template: '#lnbits-admin-funding-sources',
|
||||||
mixins: [window.windowMixin],
|
mixins: [window.windowMixin],
|
||||||
props: ['form-data', 'allowed-funding-sources'],
|
props: ['form-data', 'allowed-funding-sources'],
|
||||||
methods: {
|
methods: {
|
||||||
24
lnbits/static/js/components/admin/lnbits-admin-funding.js
Normal file
24
lnbits/static/js/components/admin/lnbits-admin-funding.js
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
window.app.component('lnbits-admin-funding', {
|
||||||
|
props: ['is-super-user', 'form-data', 'settings'],
|
||||||
|
template: '#lnbits-admin-funding',
|
||||||
|
mixins: [window.windowMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
auditData: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getAudit()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getAudit() {
|
||||||
|
LNbits.api
|
||||||
|
// TODO: should not use admin key here
|
||||||
|
.request('GET', '/admin/api/v1/audit', this.g.user.wallets[0].adminkey)
|
||||||
|
.then(response => {
|
||||||
|
this.auditData = response.data
|
||||||
|
})
|
||||||
|
.catch(LNbits.utils.notifyApiError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
74
lnbits/static/js/components/admin/lnbits-admin-library.js
Normal file
74
lnbits/static/js/components/admin/lnbits-admin-library.js
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
window.app.component('lnbits-admin-library', {
|
||||||
|
props: ['form-data'],
|
||||||
|
template: '#lnbits-admin-library',
|
||||||
|
mixins: [window.windowMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
library_images: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async created() {
|
||||||
|
await this.getUploadedImages()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onImageInput(e) {
|
||||||
|
const file = e.target.files[0]
|
||||||
|
if (file) {
|
||||||
|
this.uploadImage(file)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
uploadImage(file) {
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('file', file)
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'POST',
|
||||||
|
'/admin/api/v1/images',
|
||||||
|
this.g.user.wallets[0].adminkey,
|
||||||
|
formData,
|
||||||
|
{headers: {'Content-Type': 'multipart/form-data'}}
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
this.$q.notify({
|
||||||
|
type: 'positive',
|
||||||
|
message: 'Image uploaded!',
|
||||||
|
icon: null
|
||||||
|
})
|
||||||
|
this.getUploadedImages()
|
||||||
|
})
|
||||||
|
.catch(LNbits.utils.notifyApiError)
|
||||||
|
},
|
||||||
|
getUploadedImages() {
|
||||||
|
LNbits.api
|
||||||
|
.request('GET', '/admin/api/v1/images', this.g.user.wallets[0].inkey)
|
||||||
|
.then(response => {
|
||||||
|
this.library_images = response.data.map(image => ({
|
||||||
|
...image,
|
||||||
|
url: `${window.origin}/${image.directory}/${image.filename}`
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
.catch(LNbits.utils.notifyApiError)
|
||||||
|
},
|
||||||
|
deleteImage(filename) {
|
||||||
|
LNbits.utils
|
||||||
|
.confirmDialog('Are you sure you want to delete this image?')
|
||||||
|
.onOk(() => {
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'DELETE',
|
||||||
|
`/admin/api/v1/images/${filename}`,
|
||||||
|
this.g.user.wallets[0].adminkey
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
this.$q.notify({
|
||||||
|
type: 'positive',
|
||||||
|
message: 'Image deleted!',
|
||||||
|
icon: null
|
||||||
|
})
|
||||||
|
this.getUploadedImages()
|
||||||
|
})
|
||||||
|
.catch(LNbits.utils.notifyApiError)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
window.app.component('lnbits-admin-notifications', {
|
||||||
|
props: ['form-data'],
|
||||||
|
template: '#lnbits-admin-notifications',
|
||||||
|
mixins: [window.windowMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
nostrNotificationIdentifier: '',
|
||||||
|
emailNotificationAddress: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
sendTestEmail() {
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'GET',
|
||||||
|
'/admin/api/v1/testemail',
|
||||||
|
this.g.user.wallets[0].adminkey
|
||||||
|
)
|
||||||
|
.then(response => {
|
||||||
|
if (response.data.status === 'error') {
|
||||||
|
throw new Error(response.data.message)
|
||||||
|
}
|
||||||
|
this.$q.notify({
|
||||||
|
message: 'Test email sent!',
|
||||||
|
color: 'positive'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$q.notify({
|
||||||
|
message: error.message,
|
||||||
|
color: 'negative'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
addNostrNotificationIdentifier() {
|
||||||
|
const identifer = this.nostrNotificationIdentifier.trim()
|
||||||
|
const identifiers = this.formData.lnbits_nostr_notifications_identifiers
|
||||||
|
if (identifer && identifer.length && !identifiers.includes(identifer)) {
|
||||||
|
this.formData.lnbits_nostr_notifications_identifiers = [
|
||||||
|
...identifiers,
|
||||||
|
identifer
|
||||||
|
]
|
||||||
|
this.nostrNotificationIdentifier = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeNostrNotificationIdentifier(identifer) {
|
||||||
|
const identifiers = this.formData.lnbits_nostr_notifications_identifiers
|
||||||
|
this.formData.lnbits_nostr_notifications_identifiers = identifiers.filter(
|
||||||
|
m => m !== identifer
|
||||||
|
)
|
||||||
|
},
|
||||||
|
addEmailNotificationAddress() {
|
||||||
|
const email = this.emailNotificationAddress.trim()
|
||||||
|
const emails = this.formData.lnbits_email_notifications_to_emails
|
||||||
|
if (email && email.length && !emails.includes(email)) {
|
||||||
|
this.formData.lnbits_email_notifications_to_emails = [...emails, email]
|
||||||
|
this.emailNotificationAddress = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeEmailNotificationAddress(email) {
|
||||||
|
const emails = this.formData.lnbits_email_notifications_to_emails
|
||||||
|
this.formData.lnbits_email_notifications_to_emails = emails.filter(
|
||||||
|
m => m !== email
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
111
lnbits/static/js/components/admin/lnbits-admin-security.js
Normal file
111
lnbits/static/js/components/admin/lnbits-admin-security.js
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
window.app.component('lnbits-admin-security', {
|
||||||
|
props: ['form-data'],
|
||||||
|
template: '#lnbits-admin-security',
|
||||||
|
mixins: [window.windowMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
logs: [],
|
||||||
|
formBlockedIPs: '',
|
||||||
|
serverlogEnabled: false,
|
||||||
|
nostrAcceptedUrl: '',
|
||||||
|
formAllowedIPs: '',
|
||||||
|
formCallbackUrlRule: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {},
|
||||||
|
methods: {
|
||||||
|
addAllowedIPs() {
|
||||||
|
const allowedIPs = this.formAllowedIPs.trim()
|
||||||
|
const allowed_ips = this.formData.lnbits_allowed_ips
|
||||||
|
if (
|
||||||
|
allowedIPs &&
|
||||||
|
allowedIPs.length &&
|
||||||
|
!allowed_ips.includes(allowedIPs)
|
||||||
|
) {
|
||||||
|
this.formData.lnbits_allowed_ips = [...allowed_ips, allowedIPs]
|
||||||
|
this.formAllowedIPs = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeAllowedIPs(allowed_ip) {
|
||||||
|
const allowed_ips = this.formData.lnbits_allowed_ips
|
||||||
|
this.formData.lnbits_allowed_ips = allowed_ips.filter(
|
||||||
|
a => a !== allowed_ip
|
||||||
|
)
|
||||||
|
},
|
||||||
|
addBlockedIPs() {
|
||||||
|
const blockedIPs = this.formBlockedIPs.trim()
|
||||||
|
const blocked_ips = this.formData.lnbits_blocked_ips
|
||||||
|
if (
|
||||||
|
blockedIPs &&
|
||||||
|
blockedIPs.length &&
|
||||||
|
!blocked_ips.includes(blockedIPs)
|
||||||
|
) {
|
||||||
|
this.formData.lnbits_blocked_ips = [...blocked_ips, blockedIPs]
|
||||||
|
this.formBlockedIPs = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeBlockedIPs(blocked_ip) {
|
||||||
|
const blocked_ips = this.formData.lnbits_blocked_ips
|
||||||
|
this.formData.lnbits_blocked_ips = blocked_ips.filter(
|
||||||
|
b => b !== blocked_ip
|
||||||
|
)
|
||||||
|
},
|
||||||
|
addCallbackUrlRule() {
|
||||||
|
const allowedCallback = this.formCallbackUrlRule.trim()
|
||||||
|
const allowedCallbacks = this.formData.lnbits_callback_url_rules
|
||||||
|
if (
|
||||||
|
allowedCallback &&
|
||||||
|
allowedCallback.length &&
|
||||||
|
!allowedCallbacks.includes(allowedCallback)
|
||||||
|
) {
|
||||||
|
this.formData.lnbits_callback_url_rules = [
|
||||||
|
...allowedCallbacks,
|
||||||
|
allowedCallback
|
||||||
|
]
|
||||||
|
this.formCallbackUrlRule = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeCallbackUrlRule(allowedCallback) {
|
||||||
|
const allowedCallbacks = this.formData.lnbits_callback_url_rules
|
||||||
|
this.formData.lnbits_callback_url_rules = allowedCallbacks.filter(
|
||||||
|
a => a !== allowedCallback
|
||||||
|
)
|
||||||
|
},
|
||||||
|
addNostrUrl() {
|
||||||
|
const url = this.nostrAcceptedUrl.trim()
|
||||||
|
this.removeNostrUrl(url)
|
||||||
|
this.formData.nostr_absolute_request_urls.push(url)
|
||||||
|
this.nostrAcceptedUrl = ''
|
||||||
|
},
|
||||||
|
removeNostrUrl(url) {
|
||||||
|
this.formData.nostr_absolute_request_urls =
|
||||||
|
this.formData.nostr_absolute_request_urls.filter(b => b !== url)
|
||||||
|
},
|
||||||
|
async toggleServerLog() {
|
||||||
|
this.serverlogEnabled = !this.serverlogEnabled
|
||||||
|
if (this.serverlogEnabled) {
|
||||||
|
const wsProto = location.protocol !== 'http:' ? 'wss://' : 'ws://'
|
||||||
|
const digestHex = await LNbits.utils.digestMessage(this.g.user.id)
|
||||||
|
const localUrl =
|
||||||
|
wsProto +
|
||||||
|
document.domain +
|
||||||
|
':' +
|
||||||
|
location.port +
|
||||||
|
'/api/v1/ws/' +
|
||||||
|
digestHex
|
||||||
|
this.ws = new WebSocket(localUrl)
|
||||||
|
this.ws.addEventListener('message', async ({data}) => {
|
||||||
|
this.logs.push(data.toString())
|
||||||
|
const scrollArea = this.$refs.logScroll
|
||||||
|
if (scrollArea) {
|
||||||
|
const scrollTarget = scrollArea.getScrollTarget()
|
||||||
|
const duration = 0
|
||||||
|
scrollArea.setScrollPosition(scrollTarget.scrollHeight, duration)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.ws.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
13
lnbits/static/js/components/admin/lnbits-admin-server.js
Normal file
13
lnbits/static/js/components/admin/lnbits-admin-server.js
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
window.app.component('lnbits-admin-server', {
|
||||||
|
props: ['form-data'],
|
||||||
|
template: '#lnbits-admin-server',
|
||||||
|
mixins: [window.windowMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currencies: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async created() {
|
||||||
|
this.currencies = await LNbits.api.getCurrencies()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
window.app.component('lnbits-admin-site-customisation', {
|
||||||
|
props: ['form-data'],
|
||||||
|
template: '#lnbits-admin-site-customisation',
|
||||||
|
mixins: [window.windowMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
lnbits_theme_options: [
|
||||||
|
'classic',
|
||||||
|
'bitcoin',
|
||||||
|
'flamingo',
|
||||||
|
'cyber',
|
||||||
|
'freedom',
|
||||||
|
'mint',
|
||||||
|
'autumn',
|
||||||
|
'monochrome',
|
||||||
|
'salvador'
|
||||||
|
],
|
||||||
|
colors: [
|
||||||
|
'primary',
|
||||||
|
'secondary',
|
||||||
|
'accent',
|
||||||
|
'positive',
|
||||||
|
'negative',
|
||||||
|
'info',
|
||||||
|
'warning',
|
||||||
|
'red',
|
||||||
|
'yellow',
|
||||||
|
'orange'
|
||||||
|
],
|
||||||
|
reactionOptions: [
|
||||||
|
'none',
|
||||||
|
'confettiBothSides',
|
||||||
|
'confettiFireworks',
|
||||||
|
'confettiStars',
|
||||||
|
'confettiTop'
|
||||||
|
],
|
||||||
|
globalBorderOptions: [
|
||||||
|
'retro-border',
|
||||||
|
'hard-border',
|
||||||
|
'neon-border',
|
||||||
|
'no-border'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {}
|
||||||
|
})
|
||||||
37
lnbits/static/js/components/admin/lnbits-admin-users.js
Normal file
37
lnbits/static/js/components/admin/lnbits-admin-users.js
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
window.app.component('lnbits-admin-users', {
|
||||||
|
props: ['form-data'],
|
||||||
|
template: '#lnbits-admin-users',
|
||||||
|
mixins: [window.windowMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
formAddUser: '',
|
||||||
|
formAddAdmin: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
addAllowedUser() {
|
||||||
|
let addUser = this.formAddUser
|
||||||
|
let allowed_users = this.formData.lnbits_allowed_users
|
||||||
|
if (addUser && addUser.length && !allowed_users.includes(addUser)) {
|
||||||
|
this.formData.lnbits_allowed_users = [...allowed_users, addUser]
|
||||||
|
this.formAddUser = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeAllowedUser(user) {
|
||||||
|
let allowed_users = this.formData.lnbits_allowed_users
|
||||||
|
this.formData.lnbits_allowed_users = allowed_users.filter(u => u !== user)
|
||||||
|
},
|
||||||
|
addAdminUser() {
|
||||||
|
let addUser = this.formAddAdmin
|
||||||
|
let admin_users = this.formData.lnbits_admin_users
|
||||||
|
if (addUser && addUser.length && !admin_users.includes(addUser)) {
|
||||||
|
this.formData.lnbits_admin_users = [...admin_users, addUser]
|
||||||
|
this.formAddAdmin = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeAdminUser(user) {
|
||||||
|
let admin_users = this.formData.lnbits_admin_users
|
||||||
|
this.formData.lnbits_admin_users = admin_users.filter(u => u !== user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@ -139,15 +139,6 @@ const routes = [
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/admin',
|
|
||||||
name: 'Admin',
|
|
||||||
component: DynamicComponent,
|
|
||||||
props: {
|
|
||||||
fetchUrl: '/admin',
|
|
||||||
scripts: ['/static/js/admin.js']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/extensions',
|
path: '/extensions',
|
||||||
name: 'Extensions',
|
name: 'Extensions',
|
||||||
|
|
@ -204,6 +195,11 @@ const routes = [
|
||||||
path: '/users',
|
path: '/users',
|
||||||
name: 'Users',
|
name: 'Users',
|
||||||
component: PageUsers
|
component: PageUsers
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/admin',
|
||||||
|
name: 'Admin',
|
||||||
|
component: PageAdmin
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
122
lnbits/static/js/pages/admin.js
Normal file
122
lnbits/static/js/pages/admin.js
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
window.PageAdmin = {
|
||||||
|
template: '#page-admin',
|
||||||
|
mixins: [windowMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tab: 'funding',
|
||||||
|
settings: {},
|
||||||
|
formData: {
|
||||||
|
lnbits_exchange_rate_providers: [],
|
||||||
|
lnbits_audit_exclude_paths: [],
|
||||||
|
lnbits_audit_include_paths: [],
|
||||||
|
lnbits_audit_http_response_codes: []
|
||||||
|
},
|
||||||
|
isSuperUser: false,
|
||||||
|
needsRestart: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async created() {
|
||||||
|
await this.getSettings()
|
||||||
|
const hash = window.location.hash.replace('#', '')
|
||||||
|
if (hash) {
|
||||||
|
this.tab = hash
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
checkChanges() {
|
||||||
|
return !_.isEqual(this.settings, this.formData)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getDefaultSetting(fieldName) {
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'GET',
|
||||||
|
`/admin/api/v1/settings/default?field_name=${fieldName}`
|
||||||
|
)
|
||||||
|
.then(response => {
|
||||||
|
this.formData[fieldName] = response.data.default_value
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
LNbits.utils.notifyApiError(error)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
restartServer() {
|
||||||
|
LNbits.api
|
||||||
|
.request('GET', '/admin/api/v1/restart/')
|
||||||
|
.then(response => {
|
||||||
|
this.$q.notify({
|
||||||
|
type: 'positive',
|
||||||
|
message: 'Success! Restarted Server',
|
||||||
|
icon: null
|
||||||
|
})
|
||||||
|
this.needsRestart = false
|
||||||
|
})
|
||||||
|
.catch(LNbits.utils.notifyApiError)
|
||||||
|
},
|
||||||
|
async getSettings() {
|
||||||
|
await LNbits.api
|
||||||
|
.request(
|
||||||
|
'GET',
|
||||||
|
'/admin/api/v1/settings',
|
||||||
|
this.g.user.wallets[0].adminkey
|
||||||
|
)
|
||||||
|
.then(response => {
|
||||||
|
this.isSuperUser = response.data.is_super_user || false
|
||||||
|
this.settings = response.data
|
||||||
|
this.formData = {...this.settings}
|
||||||
|
})
|
||||||
|
.catch(LNbits.utils.notifyApiError)
|
||||||
|
},
|
||||||
|
updateSettings() {
|
||||||
|
const data = _.omit(this.formData, [
|
||||||
|
'is_super_user',
|
||||||
|
'lnbits_allowed_funding_sources',
|
||||||
|
'touch'
|
||||||
|
])
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'PUT',
|
||||||
|
'/admin/api/v1/settings',
|
||||||
|
this.g.user.wallets[0].adminkey,
|
||||||
|
data
|
||||||
|
)
|
||||||
|
.then(response => {
|
||||||
|
this.needsRestart =
|
||||||
|
this.settings.lnbits_backend_wallet_class !==
|
||||||
|
this.formData.lnbits_backend_wallet_class
|
||||||
|
this.settings = this.formData
|
||||||
|
this.formData = _.clone(this.settings)
|
||||||
|
Quasar.Notify.create({
|
||||||
|
type: 'positive',
|
||||||
|
message: `Success! Settings changed! ${
|
||||||
|
this.needsRestart ? 'Restart required!' : ''
|
||||||
|
}`,
|
||||||
|
icon: null
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(LNbits.utils.notifyApiError)
|
||||||
|
},
|
||||||
|
deleteSettings() {
|
||||||
|
LNbits.utils
|
||||||
|
.confirmDialog('Are you sure you want to restore settings to default?')
|
||||||
|
.onOk(() => {
|
||||||
|
LNbits.api
|
||||||
|
.request('DELETE', '/admin/api/v1/settings')
|
||||||
|
.then(response => {
|
||||||
|
Quasar.Notify.create({
|
||||||
|
type: 'positive',
|
||||||
|
message:
|
||||||
|
'Success! Restored settings to defaults. Restarting...',
|
||||||
|
icon: null
|
||||||
|
})
|
||||||
|
this.$q.localStorage.clear()
|
||||||
|
})
|
||||||
|
.catch(LNbits.utils.notifyApiError)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
downloadBackup() {
|
||||||
|
window.open('/admin/api/v1/backup', '_blank')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -125,6 +125,12 @@ window.windowMixin = {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
formatDate(date) {
|
||||||
|
return moment
|
||||||
|
.utc(date * 1000)
|
||||||
|
.local()
|
||||||
|
.fromNow()
|
||||||
|
},
|
||||||
formatBalance(amount) {
|
formatBalance(amount) {
|
||||||
if (LNBITS_DENOMINATION != 'sats') {
|
if (LNBITS_DENOMINATION != 'sats') {
|
||||||
return LNbits.utils.formatCurrency(amount / 100, LNBITS_DENOMINATION)
|
return LNbits.utils.formatCurrency(amount / 100, LNBITS_DENOMINATION)
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,21 @@
|
||||||
"js/pages/audit.js",
|
"js/pages/audit.js",
|
||||||
"js/pages/wallets.js",
|
"js/pages/wallets.js",
|
||||||
"js/pages/users.js",
|
"js/pages/users.js",
|
||||||
|
"js/pages/admin.js",
|
||||||
|
"js/components/admin/lnbits-admin-funding.js",
|
||||||
|
"js/components/admin/lnbits-admin-funding-sources.js",
|
||||||
|
"js/components/admin/lnbits-admin-fiat-providers.js",
|
||||||
|
"js/components/admin/lnbits-admin-exchange-providers.js",
|
||||||
|
"js/components/admin/lnbits-admin-security.js",
|
||||||
|
"js/components/admin/lnbits-admin-users.js",
|
||||||
|
"js/components/admin/lnbits-admin-server.js",
|
||||||
|
"js/components/admin/lnbits-admin-extensions.js",
|
||||||
|
"js/components/admin/lnbits-admin-notifications.js",
|
||||||
|
"js/components/admin/lnbits-admin-site-customisation.js",
|
||||||
|
"js/components/admin/lnbits-admin-library.js",
|
||||||
|
"js/components/admin/lnbits-admin-audit.js",
|
||||||
"js/components/lnbits-qrcode.js",
|
"js/components/lnbits-qrcode.js",
|
||||||
"js/components/lnbits-qrcode-lnurl.js",
|
"js/components/lnbits-qrcode-lnurl.js",
|
||||||
"js/components/lnbits-funding-sources.js",
|
|
||||||
"js/components/extension-settings.js",
|
"js/components/extension-settings.js",
|
||||||
"js/components/data-fields.js",
|
"js/components/data-fields.js",
|
||||||
"js/components/payment-list.js",
|
"js/components/payment-list.js",
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,16 @@
|
||||||
|
{% include('components/admin/funding.vue') %} {%
|
||||||
|
include('components/admin/funding_sources.vue') %} {%
|
||||||
|
include('components/admin/fiat_providers.vue') %} {%
|
||||||
|
include('components/admin/exchange_providers.vue') %} {%
|
||||||
|
include('components/admin/security.vue') %} {%
|
||||||
|
include('components/admin/users.vue') %} {%
|
||||||
|
include('components/admin/site_customisation.vue') %} {%
|
||||||
|
include('components/admin/audit.vue') %} {%
|
||||||
|
include('components/admin/extensions.vue') %} {%
|
||||||
|
include('components/admin/library.vue') %} {%
|
||||||
|
include('components/admin/notifications.vue') %} {%
|
||||||
|
include('components/admin/server.vue') %}
|
||||||
|
|
||||||
<template id="lnbits-wallet-list">
|
<template id="lnbits-wallet-list">
|
||||||
<q-list
|
<q-list
|
||||||
v-if="g.user && g.user.wallets.length"
|
v-if="g.user && g.user.wallets.length"
|
||||||
|
|
@ -1232,92 +1245,6 @@
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template id="lnbits-funding-sources">
|
|
||||||
<div class="funding-sources">
|
|
||||||
<h6 class="q-my-none q-mb-sm">
|
|
||||||
<span v-text="$t('funding_sources')"></span>
|
|
||||||
<q-btn
|
|
||||||
round
|
|
||||||
flat
|
|
||||||
@click="this.hideInput = !this.hideInput"
|
|
||||||
:icon="this.hideInput ? 'visibility_off' : 'visibility'"
|
|
||||||
></q-btn>
|
|
||||||
</h6>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12">
|
|
||||||
<p>Active Funding<small> (Requires server restart)</small></p>
|
|
||||||
<q-select
|
|
||||||
filled
|
|
||||||
v-model="formData.lnbits_backend_wallet_class"
|
|
||||||
hint="Select the active funding wallet"
|
|
||||||
:options="sortedAllowedFundingSources"
|
|
||||||
:option-label="item => getFundingSourceLabel(item)"
|
|
||||||
></q-select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<q-list
|
|
||||||
class="q-mt-md"
|
|
||||||
v-for="(fund, idx) in allowedFundingSources"
|
|
||||||
:key="idx"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="
|
|
||||||
fundingSources.get(fund) &&
|
|
||||||
fund === formData.lnbits_backend_wallet_class
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="row"
|
|
||||||
v-for="([key, prop], i) in Object.entries(fundingSources.get(fund))"
|
|
||||||
:key="i"
|
|
||||||
>
|
|
||||||
<div class="col-12">
|
|
||||||
<q-input
|
|
||||||
v-model="formData[key]"
|
|
||||||
filled
|
|
||||||
class="q-mt-sm"
|
|
||||||
:type="hideInput ? 'password' : 'text'"
|
|
||||||
:label="prop.label"
|
|
||||||
:hint="prop.hint"
|
|
||||||
:readonly="prop.readonly || false"
|
|
||||||
>
|
|
||||||
<q-btn
|
|
||||||
v-if="prop.copy"
|
|
||||||
@click="copyText(formData[key])"
|
|
||||||
icon="content_copy"
|
|
||||||
class="cursor-pointer"
|
|
||||||
color="grey"
|
|
||||||
flat
|
|
||||||
dense
|
|
||||||
></q-btn>
|
|
||||||
<q-btn
|
|
||||||
v-if="prop.qrcode"
|
|
||||||
@click="showQRValue(formData[key])"
|
|
||||||
icon="qr_code"
|
|
||||||
class="cursor-pointer"
|
|
||||||
color="grey"
|
|
||||||
flat
|
|
||||||
dense
|
|
||||||
></q-btn>
|
|
||||||
</q-input>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</q-list>
|
|
||||||
<q-dialog v-model="showQRDialog">
|
|
||||||
<q-card class="q-pa-md">
|
|
||||||
<q-card-section>
|
|
||||||
<lnbits-qrcode :value="qrValue"></lnbits-qrcode>
|
|
||||||
</q-card-section>
|
|
||||||
<q-card-actions align="right">
|
|
||||||
<q-btn flat :label="$t('close')" v-close-popup />
|
|
||||||
</q-card-actions>
|
|
||||||
</q-card>
|
|
||||||
</q-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template id="user-id-only">
|
<template id="user-id-only">
|
||||||
<div v-if="authAction === 'login' && authMethod === 'user-id-only'">
|
<div v-if="authAction === 'login' && authMethod === 'user-id-only'">
|
||||||
<q-card-section class="q-pb-none">
|
<q-card-section class="q-pb-none">
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<q-tab-panel name="audit">
|
<template id="lnbits-admin-audit">
|
||||||
<q-card-section class="q-pa-none">
|
<q-card-section class="q-pa-none">
|
||||||
<h6 class="q-my-none q-mb-sm">Audit</h6>
|
<h6 class="q-my-none q-mb-sm">Audit</h6>
|
||||||
|
|
||||||
<div class="row q-mb-lg">
|
<div class="row q-mb-lg">
|
||||||
<div class="col-md-6 col-sm-12 q-pr-sm">
|
<div class="col-md-6 col-sm-12 q-pr-sm">
|
||||||
<q-item tag="label" v-ripple>
|
<q-item tag="label" v-ripple>
|
||||||
|
|
@ -50,8 +49,12 @@
|
||||||
<span v-text="$t('audit_record_warning')"></span>
|
<span v-text="$t('audit_record_warning')"></span>
|
||||||
<br />
|
<br />
|
||||||
<ul>
|
<ul>
|
||||||
<li><span v-text="$t('audit_record_req_warning_1')"></span></li>
|
<li>
|
||||||
<li><span v-text="$t('audit_record_req_warning_2')"></span></li>
|
<span v-text="$t('audit_record_req_warning_1')"></span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span v-text="$t('audit_record_req_warning_2')"></span>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<br />
|
<br />
|
||||||
<span v-text="$t('audit_record_use')"></span>
|
<span v-text="$t('audit_record_use')"></span>
|
||||||
|
|
@ -133,7 +136,15 @@
|
||||||
multiple
|
multiple
|
||||||
:hint="$t('audit_http_methods_hint')"
|
:hint="$t('audit_http_methods_hint')"
|
||||||
:label="$t('audit_http_methods_label')"
|
:label="$t('audit_http_methods_label')"
|
||||||
:options="['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']"
|
:options="[
|
||||||
|
'GET',
|
||||||
|
'POST',
|
||||||
|
'PUT',
|
||||||
|
'PATCH',
|
||||||
|
'DELETE',
|
||||||
|
'HEAD',
|
||||||
|
'OPTIONS'
|
||||||
|
]"
|
||||||
></q-select>
|
></q-select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 col-sm-12 q-pr-sm">
|
<div class="col-md-6 col-sm-12 q-pr-sm">
|
||||||
|
|
@ -225,4 +236,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-tab-panel>
|
</template>
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<q-tab-panel name="exchange_providers">
|
<template id="lnbits-admin-exchange-providers">
|
||||||
<h6 class="q-my-none q-mb-sm">
|
<h6 class="q-my-none q-mb-sm">
|
||||||
<span v-text="$t('exchange_providers')"></span>
|
<span v-text="$t('exchange_providers')"></span>
|
||||||
</h6>
|
</h6>
|
||||||
|
|
@ -109,7 +109,7 @@
|
||||||
dense
|
dense
|
||||||
filled
|
filled
|
||||||
v-model="props.row.name"
|
v-model="props.row.name"
|
||||||
@update:model-value="touchSettings()"
|
@update:model-value="formData.touch = null"
|
||||||
type="text"
|
type="text"
|
||||||
>
|
>
|
||||||
</q-input>
|
</q-input>
|
||||||
|
|
@ -119,7 +119,7 @@
|
||||||
dense
|
dense
|
||||||
filled
|
filled
|
||||||
v-model="props.row.api_url"
|
v-model="props.row.api_url"
|
||||||
@update:model-value="touchSettings()"
|
@update:model-value="formData.touch = null"
|
||||||
type="text"
|
type="text"
|
||||||
>
|
>
|
||||||
</q-input
|
</q-input
|
||||||
|
|
@ -129,7 +129,7 @@
|
||||||
dense
|
dense
|
||||||
filled
|
filled
|
||||||
v-model="props.row.path"
|
v-model="props.row.path"
|
||||||
@update:model-value="touchSettings()"
|
@update:model-value="formData.touch = null"
|
||||||
type="text"
|
type="text"
|
||||||
>
|
>
|
||||||
</q-input>
|
</q-input>
|
||||||
|
|
@ -139,9 +139,9 @@
|
||||||
filled
|
filled
|
||||||
dense
|
dense
|
||||||
v-model="props.row.exclude_to"
|
v-model="props.row.exclude_to"
|
||||||
@update:model-value="touchSettings()"
|
@update:model-value="formData.touch = null"
|
||||||
multiple
|
multiple
|
||||||
:options="{{ currencies | safe }}"
|
:options="currencies"
|
||||||
></q-select>
|
></q-select>
|
||||||
</q-td>
|
</q-td>
|
||||||
<q-td>
|
<q-td>
|
||||||
|
|
@ -155,7 +155,7 @@
|
||||||
>
|
>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
<q-chip
|
<q-chip
|
||||||
v-for="ticker, index in props.row.ticker_conversion"
|
v-for="(ticker, index) in props.row.ticker_conversion"
|
||||||
:key="ticker"
|
:key="ticker"
|
||||||
removable
|
removable
|
||||||
dense
|
dense
|
||||||
|
|
@ -198,4 +198,47 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-8 col-sm-12"></div>
|
<div class="col-md-8 col-sm-12"></div>
|
||||||
</div>
|
</div>
|
||||||
</q-tab-panel>
|
|
||||||
|
<q-dialog v-model="exchangeData.showTickerConversion" position="top">
|
||||||
|
<q-card class="q-pa-md q-pt-md lnbits__dialog-card">
|
||||||
|
<div class="q-mb-md">
|
||||||
|
<strong v-text="$t('create_ticker_converter')"></strong>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 q-mb-md">
|
||||||
|
<q-select
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
v-model="exchangeData.convertFromTicker"
|
||||||
|
label="From Currency"
|
||||||
|
:options="currencies"
|
||||||
|
></q-select>
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<q-input
|
||||||
|
v-model="exchangeData.convertToTicker"
|
||||||
|
dense
|
||||||
|
filled
|
||||||
|
label="New Ticker"
|
||||||
|
hint="This ticker will be used for the exchange API calls."
|
||||||
|
>
|
||||||
|
</q-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row q-mt-lg">
|
||||||
|
<q-btn
|
||||||
|
@click="addExchangeTickerConversion()"
|
||||||
|
label="Add Ticker Conversion"
|
||||||
|
color="primary"
|
||||||
|
></q-btn>
|
||||||
|
<q-btn
|
||||||
|
v-close-popup
|
||||||
|
flat
|
||||||
|
color="grey"
|
||||||
|
class="q-ml-auto"
|
||||||
|
v-text="$t('close')"
|
||||||
|
></q-btn>
|
||||||
|
</div>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
</template>
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<q-tab-panel name="extensions">
|
<template id="lnbits-admin-extensions">
|
||||||
<q-card-section class="q-pa-none">
|
<q-card-section class="q-pa-none">
|
||||||
<div>
|
<div>
|
||||||
<h6 class="q-my-none">
|
<h6 class="q-my-none">
|
||||||
|
|
@ -140,4 +140,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-tab-panel>
|
</template>
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
<q-tab-panel name="fiat_providers">
|
<template id="lnbits-admin-fiat-providers">
|
||||||
<h6 class="q-my-none q-mb-sm">
|
<h6 class="q-my-none q-mb-sm">
|
||||||
<span v-text="$t('fiat_providers')"></span>
|
<span v-text="$t('fiat_providers')"></span>
|
||||||
<q-btn
|
<q-btn
|
||||||
round
|
round
|
||||||
flat
|
flat
|
||||||
@click="hideInputsToggle()"
|
@click="hideInputToggle = !hideInputToggle"
|
||||||
:icon="hideInputToggle ? 'visibility_off' : 'visibility'"
|
:icon="hideInputToggle ? 'visibility_off' : 'visibility'"
|
||||||
></q-btn>
|
></q-btn>
|
||||||
</h6>
|
</h6>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-list bordered class="rounded-borders">
|
<q-list bordered class="rounded-borders">
|
||||||
|
|
@ -16,9 +15,7 @@
|
||||||
<template v-slot:header>
|
<template v-slot:header>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-avatar>
|
<q-avatar>
|
||||||
<img
|
<img src="/static/images/stripe_logo.ico" />
|
||||||
:src="'{{ static_url_for('static', 'images/stripe_logo.ico') }}'"
|
|
||||||
/>
|
|
||||||
</q-avatar>
|
</q-avatar>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
|
|
||||||
|
|
@ -103,7 +100,9 @@
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<span v-text="$t('webhook_events_list')"></span>
|
<span v-text="$t('webhook_events_list')"></span>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>checkout.session.completed</code></li>
|
<li>
|
||||||
|
<code>checkout.session.completed</code>
|
||||||
|
</li>
|
||||||
- the user completed the checkout process
|
- the user completed the checkout process
|
||||||
<li><code>invoice.paid</code></li>
|
<li><code>invoice.paid</code></li>
|
||||||
- the invoice was successfully paid (for subscriptions)
|
- the invoice was successfully paid (for subscriptions)
|
||||||
|
|
@ -120,7 +119,7 @@
|
||||||
type="number"
|
type="number"
|
||||||
min="0"
|
min="0"
|
||||||
v-model="formData.stripe_limits.service_fee_percent"
|
v-model="formData.stripe_limits.service_fee_percent"
|
||||||
@update:model-value="touchSettings()"
|
@update:model-value="formData.touch = null"
|
||||||
:label="$t('service_fee_label')"
|
:label="$t('service_fee_label')"
|
||||||
:hint="$t('service_fee_hint')"
|
:hint="$t('service_fee_hint')"
|
||||||
></q-input>
|
></q-input>
|
||||||
|
|
@ -132,7 +131,7 @@
|
||||||
type="number"
|
type="number"
|
||||||
min="0"
|
min="0"
|
||||||
v-model="formData.stripe_limits.service_max_fee_sats"
|
v-model="formData.stripe_limits.service_max_fee_sats"
|
||||||
@update:model-value="touchSettings()"
|
@update:model-value="formData.touch = null"
|
||||||
:label="$t('service_fee_max')"
|
:label="$t('service_fee_max')"
|
||||||
:hint="$t('service_fee_max_hint')"
|
:hint="$t('service_fee_max_hint')"
|
||||||
></q-input>
|
></q-input>
|
||||||
|
|
@ -143,7 +142,7 @@
|
||||||
class="q-ma-sm"
|
class="q-ma-sm"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="formData.stripe_limits.service_fee_wallet_id"
|
v-model="formData.stripe_limits.service_fee_wallet_id"
|
||||||
@update:model-value="touchSettings()"
|
@update:model-value="formData.touch = null"
|
||||||
:label="$t('fee_wallet_label')"
|
:label="$t('fee_wallet_label')"
|
||||||
:hint="$t('fee_wallet_hint')"
|
:hint="$t('fee_wallet_hint')"
|
||||||
></q-input>
|
></q-input>
|
||||||
|
|
@ -161,7 +160,7 @@
|
||||||
type="number"
|
type="number"
|
||||||
min="0"
|
min="0"
|
||||||
v-model="formData.stripe_limits.service_min_amount_sats"
|
v-model="formData.stripe_limits.service_min_amount_sats"
|
||||||
@update:model-value="touchSettings()"
|
@update:model-value="formData.touch = null"
|
||||||
:label="$t('min_incoming_payment_amount')"
|
:label="$t('min_incoming_payment_amount')"
|
||||||
:hint="$t('min_incoming_payment_amount_desc')"
|
:hint="$t('min_incoming_payment_amount_desc')"
|
||||||
></q-input>
|
></q-input>
|
||||||
|
|
@ -173,7 +172,7 @@
|
||||||
type="number"
|
type="number"
|
||||||
min="0"
|
min="0"
|
||||||
v-model="formData.stripe_limits.service_max_amount_sats"
|
v-model="formData.stripe_limits.service_max_amount_sats"
|
||||||
@update:model-value="touchSettings()"
|
@update:model-value="formData.touch = null"
|
||||||
:label="$t('max_incoming_payment_amount')"
|
:label="$t('max_incoming_payment_amount')"
|
||||||
:hint="$t('max_incoming_payment_amount_desc')"
|
:hint="$t('max_incoming_payment_amount_desc')"
|
||||||
></q-input>
|
></q-input>
|
||||||
|
|
@ -183,7 +182,7 @@
|
||||||
filled
|
filled
|
||||||
class="q-ma-sm"
|
class="q-ma-sm"
|
||||||
v-model="formData.stripe_limits.service_faucet_wallet_id"
|
v-model="formData.stripe_limits.service_faucet_wallet_id"
|
||||||
@update:model-value="touchSettings()"
|
@update:model-value="formData.touch = null"
|
||||||
:label="$t('faucest_wallet_id')"
|
:label="$t('faucest_wallet_id')"
|
||||||
:hint="$t('faucest_wallet_id_hint')"
|
:hint="$t('faucest_wallet_id_hint')"
|
||||||
></q-input>
|
></q-input>
|
||||||
|
|
@ -196,12 +195,20 @@
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<span
|
<span
|
||||||
v-text="$t('faucest_wallet_desc_1', {provider: 'stripe'})"
|
v-text="
|
||||||
|
$t('faucest_wallet_desc_1', {
|
||||||
|
provider: 'stripe'
|
||||||
|
})
|
||||||
|
"
|
||||||
></span>
|
></span>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span
|
<span
|
||||||
v-text="$t('faucest_wallet_desc_2', {provider: 'stripe'})"
|
v-text="
|
||||||
|
$t('faucest_wallet_desc_2', {
|
||||||
|
provider: 'stripe'
|
||||||
|
})
|
||||||
|
"
|
||||||
></span>
|
></span>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
|
@ -209,7 +216,11 @@
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span
|
<span
|
||||||
v-text="$t('faucest_wallet_desc_4', {provider: 'stripe'})"
|
v-text="
|
||||||
|
$t('faucest_wallet_desc_4', {
|
||||||
|
provider: 'stripe'
|
||||||
|
})
|
||||||
|
"
|
||||||
></span>
|
></span>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
|
@ -227,10 +238,14 @@
|
||||||
<q-input
|
<q-input
|
||||||
filled
|
filled
|
||||||
v-model="formAddStripeUser"
|
v-model="formAddStripeUser"
|
||||||
@keydown.enter="addAllowedUser"
|
@keydown.enter="addStripeAllowedUser"
|
||||||
type="text"
|
type="text"
|
||||||
:label="$t('allowed_users_label')"
|
:label="$t('allowed_users_label')"
|
||||||
:hint="$t('allowed_users_hint_feature', {feature: 'Stripe'})"
|
:hint="
|
||||||
|
$t('allowed_users_hint_feature', {
|
||||||
|
feature: 'Stripe'
|
||||||
|
})
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<q-btn
|
<q-btn
|
||||||
@click="addStripeAllowedUser"
|
@click="addStripeAllowedUser"
|
||||||
|
|
@ -242,7 +257,7 @@
|
||||||
<div>
|
<div>
|
||||||
<q-chip
|
<q-chip
|
||||||
v-for="user in formData.stripe_limits.allowed_users"
|
v-for="user in formData.stripe_limits.allowed_users"
|
||||||
@update:model-value="touchSettings()"
|
@update:model-value="formData.touch = null"
|
||||||
:key="user"
|
:key="user"
|
||||||
removable
|
removable
|
||||||
@remove="removeStripeAllowedUser(user)"
|
@remove="removeStripeAllowedUser(user)"
|
||||||
|
|
@ -264,9 +279,7 @@
|
||||||
<template v-slot:header>
|
<template v-slot:header>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-avatar>
|
<q-avatar>
|
||||||
<img
|
<img src="/static/images/square_logo.png" />
|
||||||
:src="'{{ static_url_for('static', 'images/square_logo.png') }}'"
|
|
||||||
/>
|
|
||||||
</q-avatar>
|
</q-avatar>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
|
|
||||||
|
|
@ -284,4 +297,4 @@
|
||||||
</q-list>
|
</q-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-tab-panel>
|
</template>
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<q-tab-panel name="funding">
|
<template id="lnbits-admin-funding">
|
||||||
<q-card-section class="q-pa-none">
|
<q-card-section class="q-pa-none">
|
||||||
<h6 class="q-my-none">
|
<h6 class="q-my-none">
|
||||||
<span v-text="$t('wallets_management')"></span>
|
<span v-text="$t('wallets_management')"></span>
|
||||||
|
|
@ -12,27 +12,48 @@
|
||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li
|
<li
|
||||||
v-text="$t('funding_source', {wallet_class: settings.lnbits_backend_wallet_class})"
|
v-text="
|
||||||
|
$t('funding_source', {
|
||||||
|
wallet_class: settings.lnbits_backend_wallet_class
|
||||||
|
})
|
||||||
|
"
|
||||||
></li>
|
></li>
|
||||||
<li
|
<li
|
||||||
v-text="$t('node_balance', {balance: (auditData.node_balance_sats || 0).toLocaleString()})"
|
v-text="
|
||||||
|
$t('node_balance', {
|
||||||
|
balance: (auditData.node_balance_sats || 0).toLocaleString()
|
||||||
|
})
|
||||||
|
"
|
||||||
></li>
|
></li>
|
||||||
<li
|
<li
|
||||||
v-text="$t('lnbits_balance', {balance: (auditData.lnbits_balance_sats || 0).toLocaleString()})"
|
v-text="
|
||||||
|
$t('lnbits_balance', {
|
||||||
|
balance: (auditData.lnbits_balance_sats || 0).toLocaleString()
|
||||||
|
})
|
||||||
|
"
|
||||||
></li>
|
></li>
|
||||||
<li
|
<li
|
||||||
v-text="$t('funding_reserve_percent', {
|
v-text="
|
||||||
percent: auditData.lnbits_balance_sats > 0
|
$t('funding_reserve_percent', {
|
||||||
? (auditData.node_balance_sats / auditData.lnbits_balance_sats * 100).toFixed(2)
|
percent:
|
||||||
|
auditData.lnbits_balance_sats > 0
|
||||||
|
? (
|
||||||
|
(auditData.node_balance_sats /
|
||||||
|
auditData.lnbits_balance_sats) *
|
||||||
|
100
|
||||||
|
).toFixed(2)
|
||||||
: 100
|
: 100
|
||||||
})"
|
})
|
||||||
|
"
|
||||||
></li>
|
></li>
|
||||||
</ul>
|
</ul>
|
||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
{% if LNBITS_NODE_UI_AVAILABLE %}
|
<div v-if="LNBITS_NODE_UI">
|
||||||
<p><span v-text="$t('node_management')"></span></p>
|
<p>
|
||||||
|
<span v-text="$t('node_management')"></span>
|
||||||
|
</p>
|
||||||
<q-toggle
|
<q-toggle
|
||||||
:label="$t('toggle_node_ui')"
|
:label="$t('toggle_node_ui')"
|
||||||
v-model="formData.lnbits_node_ui"
|
v-model="formData.lnbits_node_ui"
|
||||||
|
|
@ -48,9 +69,10 @@
|
||||||
:label="$t('toggle_transactions_node_ui')"
|
:label="$t('toggle_transactions_node_ui')"
|
||||||
v-model="formData.lnbits_node_ui_transactions"
|
v-model="formData.lnbits_node_ui_transactions"
|
||||||
></q-toggle>
|
></q-toggle>
|
||||||
{% else %}
|
</div>
|
||||||
<p><span v-text="$t('node_management_not_supported')"></span></p>
|
<p v-if="!LNBITS_NODE_UI">
|
||||||
{% endif %}
|
<span v-text="$t('node_management_not_supported')"></span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row q-col-gutter-md">
|
<div class="row q-col-gutter-md">
|
||||||
|
|
@ -66,7 +88,9 @@
|
||||||
</q-input>
|
</q-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-3">
|
<div class="col-12 col-md-3">
|
||||||
<p><span v-text="$t('fee_reserve_percent')"></span></p>
|
<p>
|
||||||
|
<span v-text="$t('fee_reserve_percent')"></span>
|
||||||
|
</p>
|
||||||
<q-input
|
<q-input
|
||||||
type="number"
|
type="number"
|
||||||
filled
|
filled
|
||||||
|
|
@ -88,7 +112,9 @@
|
||||||
</q-input>
|
</q-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-3">
|
<div class="col-12 col-md-3">
|
||||||
<p><span v-text="$t('payment_wait_time')"></span></p>
|
<p>
|
||||||
|
<span v-text="$t('payment_wait_time')"></span>
|
||||||
|
</p>
|
||||||
<q-input
|
<q-input
|
||||||
type="number"
|
type="number"
|
||||||
filled
|
filled
|
||||||
|
|
@ -102,7 +128,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isSuperUser">
|
<div v-if="isSuperUser">
|
||||||
<lnbits-funding-sources
|
<lnbits-admin-funding-sources
|
||||||
:form-data="formData"
|
:form-data="formData"
|
||||||
:allowed-funding-sources="settings.lnbits_allowed_funding_sources"
|
:allowed-funding-sources="settings.lnbits_allowed_funding_sources"
|
||||||
/>
|
/>
|
||||||
|
|
@ -215,4 +241,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-tab-panel>
|
</template>
|
||||||
85
lnbits/templates/components/admin/funding_sources.vue
Normal file
85
lnbits/templates/components/admin/funding_sources.vue
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
<template id="lnbits-admin-funding-sources">
|
||||||
|
<div class="funding-sources">
|
||||||
|
<h6 class="q-my-none q-mb-sm">
|
||||||
|
<span v-text="$t('funding_sources')"></span>
|
||||||
|
<q-btn
|
||||||
|
round
|
||||||
|
flat
|
||||||
|
@click="this.hideInput = !this.hideInput"
|
||||||
|
:icon="this.hideInput ? 'visibility_off' : 'visibility'"
|
||||||
|
></q-btn>
|
||||||
|
</h6>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<p>Active Funding<small> (Requires server restart)</small></p>
|
||||||
|
<q-select
|
||||||
|
filled
|
||||||
|
v-model="formData.lnbits_backend_wallet_class"
|
||||||
|
hint="Select the active funding wallet"
|
||||||
|
:options="sortedAllowedFundingSources"
|
||||||
|
:option-label="item => getFundingSourceLabel(item)"
|
||||||
|
></q-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<q-list
|
||||||
|
class="q-mt-md"
|
||||||
|
v-for="(fund, idx) in allowedFundingSources"
|
||||||
|
:key="idx"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="
|
||||||
|
fundingSources.get(fund) &&
|
||||||
|
fund === formData.lnbits_backend_wallet_class
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="row"
|
||||||
|
v-for="([key, prop], i) in Object.entries(fundingSources.get(fund))"
|
||||||
|
:key="i"
|
||||||
|
>
|
||||||
|
<div class="col-12">
|
||||||
|
<q-input
|
||||||
|
v-model="formData[key]"
|
||||||
|
filled
|
||||||
|
class="q-mt-sm"
|
||||||
|
:type="hideInput ? 'password' : 'text'"
|
||||||
|
:label="prop.label"
|
||||||
|
:hint="prop.hint"
|
||||||
|
:readonly="prop.readonly || false"
|
||||||
|
>
|
||||||
|
<q-btn
|
||||||
|
v-if="prop.copy"
|
||||||
|
@click="copyText(formData[key])"
|
||||||
|
icon="content_copy"
|
||||||
|
class="cursor-pointer"
|
||||||
|
color="grey"
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
></q-btn>
|
||||||
|
<q-btn
|
||||||
|
v-if="prop.qrcode"
|
||||||
|
@click="showQRValue(formData[key])"
|
||||||
|
icon="qr_code"
|
||||||
|
class="cursor-pointer"
|
||||||
|
color="grey"
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
></q-btn>
|
||||||
|
</q-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-list>
|
||||||
|
<q-dialog v-model="showQRDialog">
|
||||||
|
<q-card class="q-pa-md">
|
||||||
|
<q-card-section>
|
||||||
|
<lnbits-qrcode :value="qrValue"></lnbits-qrcode>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<q-btn flat :label="$t('close')" v-close-popup />
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<q-tab-panel name="library">
|
<template id="lnbits-admin-library">
|
||||||
<q-card-section class="q-pa-none">
|
<q-card-section class="q-pa-none">
|
||||||
<h6 class="q-my-none q-mb-sm">
|
<h6 class="q-my-none q-mb-sm">
|
||||||
<span v-text="$t('image_library')"></span>
|
<span v-text="$t('image_library')"></span>
|
||||||
|
|
@ -64,4 +64,4 @@
|
||||||
<div v-if="library_images.length === 0" class="q-pa-xl">
|
<div v-if="library_images.length === 0" class="q-pa-xl">
|
||||||
<div class="text-subtitle2 text-grey">No images uploaded yet.</div>
|
<div class="text-subtitle2 text-grey">No images uploaded yet.</div>
|
||||||
</div>
|
</div>
|
||||||
</q-tab-panel>
|
</template>
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<q-tab-panel name="notifications">
|
<template id="lnbits-admin-notifications">
|
||||||
<q-card-section class="q-pa-none">
|
<q-card-section class="q-pa-none">
|
||||||
<h6 class="q-my-none q-mb-sm">
|
<h6 class="q-my-none q-mb-sm">
|
||||||
<span v-text="$t('notifications_configure')"></span>
|
<span v-text="$t('notifications_configure')"></span>
|
||||||
|
|
@ -478,7 +478,9 @@
|
||||||
type="number"
|
type="number"
|
||||||
min="0"
|
min="0"
|
||||||
filled
|
filled
|
||||||
v-model="formData.lnbits_notification_incoming_payment_amount_sats"
|
v-model="
|
||||||
|
formData.lnbits_notification_incoming_payment_amount_sats
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
|
@ -501,11 +503,13 @@
|
||||||
type="number"
|
type="number"
|
||||||
min="0"
|
min="0"
|
||||||
filled
|
filled
|
||||||
v-model="formData.lnbits_notification_outgoing_payment_amount_sats"
|
v-model="
|
||||||
|
formData.lnbits_notification_outgoing_payment_amount_sats
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-tab-panel>
|
</template>
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<q-tab-panel name="security">
|
<template id="lnbits-admin-security">
|
||||||
<q-card-section class="q-pa-none">
|
<q-card-section class="q-pa-none">
|
||||||
<h6 class="q-my-none"><span v-text="$t('server_management')"></span></h6>
|
<h6 class="q-my-none">
|
||||||
|
<span v-text="$t('server_management')"></span>
|
||||||
|
</h6>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<p><span v-text="$t('base_url')"></span></p>
|
<p><span v-text="$t('base_url')"></span></p>
|
||||||
|
|
@ -34,7 +36,10 @@
|
||||||
:hint="$t('auth_allowed_methods_hint')"
|
:hint="$t('auth_allowed_methods_hint')"
|
||||||
:label="$t('auth_allowed_methods_label')"
|
:label="$t('auth_allowed_methods_label')"
|
||||||
:options="formData.auth_all_methods"
|
:options="formData.auth_all_methods"
|
||||||
:option-label="option => option.length > 25 ? option.substring(0, 22) + '...' : option"
|
:option-label="
|
||||||
|
option =>
|
||||||
|
option.length > 25 ? option.substring(0, 22) + '...' : option
|
||||||
|
"
|
||||||
></q-select>
|
></q-select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -206,7 +211,11 @@
|
||||||
dense
|
dense
|
||||||
flat
|
flat
|
||||||
color="primary"
|
color="primary"
|
||||||
:label="(serverlogEnabled) ? $t('disable_server_log') : $t('enable_server_log')"
|
:label="
|
||||||
|
serverlogEnabled
|
||||||
|
? $t('disable_server_log')
|
||||||
|
: $t('enable_server_log')
|
||||||
|
"
|
||||||
></q-btn>
|
></q-btn>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
|
@ -337,4 +346,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-tab-panel>
|
</template>
|
||||||
|
|
@ -1,37 +1,51 @@
|
||||||
<q-tab-panel name="server">
|
<template id="lnbits-admin-server">
|
||||||
<q-card-section class="q-pa-none">
|
<q-card-section class="q-pa-none">
|
||||||
<div>
|
<div>
|
||||||
<h6 class="q-my-none"><span v-text="$t('currency_settings')"></span></h6>
|
<h6 class="q-my-none">
|
||||||
|
<span v-text="$t('currency_settings')"></span>
|
||||||
|
</h6>
|
||||||
<div class="row q-col-gutter-md">
|
<div class="row q-col-gutter-md">
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<p><span v-text="$t('allowed_currencies')"></span></p>
|
<p>
|
||||||
|
<span v-text="$t('allowed_currencies')"></span>
|
||||||
|
</p>
|
||||||
<q-select
|
<q-select
|
||||||
filled
|
filled
|
||||||
v-model="formData.lnbits_allowed_currencies"
|
v-model="formData.lnbits_allowed_currencies"
|
||||||
multiple
|
multiple
|
||||||
:hint="$t('allowed_currencies_hint')"
|
:hint="$t('allowed_currencies_hint')"
|
||||||
:label="$t('allowed_currencies')"
|
:label="$t('allowed_currencies')"
|
||||||
:options="{{ currencies | safe }}"
|
:options="currencies"
|
||||||
></q-select>
|
></q-select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<p><span v-text="$t('default_account_currency')"></span></p>
|
<p>
|
||||||
|
<span v-text="$t('default_account_currency')"></span>
|
||||||
|
</p>
|
||||||
<q-select
|
<q-select
|
||||||
filled
|
filled
|
||||||
v-model="formData.lnbits_default_accounting_currency"
|
v-model="formData.lnbits_default_accounting_currency"
|
||||||
clearable
|
clearable
|
||||||
:hint="$t('default_account_currency_hint')"
|
:hint="$t('default_account_currency_hint')"
|
||||||
:label="$t('currency')"
|
:label="$t('currency')"
|
||||||
:options="formData.lnbits_allowed_currencies?.length ? formData.lnbits_allowed_currencies : {{ currencies }}"
|
:options="
|
||||||
|
formData.lnbits_allowed_currencies?.length
|
||||||
|
? formData.lnbits_allowed_currencies
|
||||||
|
: currencies
|
||||||
|
"
|
||||||
></q-select>
|
></q-select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<q-separator class="q-mb-lg q-mt-sm"></q-separator>
|
<q-separator class="q-mb-lg q-mt-sm"></q-separator>
|
||||||
<h6 class="q-my-none"><span v-text="$t('payments')"></span></h6>
|
<h6 class="q-my-none">
|
||||||
|
<span v-text="$t('payments')"></span>
|
||||||
|
</h6>
|
||||||
<div class="row q-col-gutter-md">
|
<div class="row q-col-gutter-md">
|
||||||
<div class="col-12 col-md-3">
|
<div class="col-12 col-md-3">
|
||||||
<p><span v-text="$t('max_outgoing_payment_amount')"></span></p>
|
<p>
|
||||||
|
<span v-text="$t('max_outgoing_payment_amount')"></span>
|
||||||
|
</p>
|
||||||
<q-input
|
<q-input
|
||||||
filled
|
filled
|
||||||
type="number"
|
type="number"
|
||||||
|
|
@ -44,7 +58,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12 col-md-3">
|
<div class="col-12 col-md-3">
|
||||||
<p><span v-text="$t('max_incoming_payment_amount')"></span></p>
|
<p>
|
||||||
|
<span v-text="$t('max_incoming_payment_amount')"></span>
|
||||||
|
</p>
|
||||||
<q-input
|
<q-input
|
||||||
filled
|
filled
|
||||||
type="number"
|
type="number"
|
||||||
|
|
@ -59,7 +75,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<q-separator class="q-mb-lg q-mt-sm"></q-separator>
|
<q-separator class="q-mb-lg q-mt-sm"></q-separator>
|
||||||
<h6 class="q-my-none"><span v-text="$t('wallet_limiter')"></span></h6>
|
<h6 class="q-my-none">
|
||||||
|
<span v-text="$t('wallet_limiter')"></span>
|
||||||
|
</h6>
|
||||||
<div class="row q-col-gutter-md">
|
<div class="row q-col-gutter-md">
|
||||||
<div class="col-12 col-md-3">
|
<div class="col-12 col-md-3">
|
||||||
<q-input
|
<q-input
|
||||||
|
|
@ -95,7 +113,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<q-separator class="q-mb-lg q-mt-sm"></q-separator>
|
<q-separator class="q-mb-lg q-mt-sm"></q-separator>
|
||||||
<h6 class="q-my-none"><span v-text="$t('service_fee')"></span></h6>
|
<h6 class="q-my-none">
|
||||||
|
<span v-text="$t('service_fee')"></span>
|
||||||
|
</h6>
|
||||||
<div class="row q-col-gutter-md">
|
<div class="row q-col-gutter-md">
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<p><span v-text="$t('service_fee')"></span></p>
|
<p><span v-text="$t('service_fee')"></span></p>
|
||||||
|
|
@ -131,7 +151,9 @@
|
||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<p><span v-text="$t('disable_fee_internal')"></span></p>
|
<p>
|
||||||
|
<span v-text="$t('disable_fee_internal')"></span>
|
||||||
|
</p>
|
||||||
<q-item tag="label" v-ripple>
|
<q-item tag="label" v-ripple>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label v-text="$t('disable_fee')"></q-item-label>
|
<q-item-label v-text="$t('disable_fee')"></q-item-label>
|
||||||
|
|
@ -155,4 +177,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-tab-panel>
|
</template>
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<q-tab-panel name="site_customisation">
|
<template id="lnbits-admin-site-customisation">
|
||||||
<q-card-section class="q-pa-none">
|
<q-card-section class="q-pa-none">
|
||||||
<h6 class="q-my-none"><span v-text="$t('ui_management')"></span></h6>
|
<h6 class="q-my-none">
|
||||||
|
<span v-text="$t('ui_management')"></span>
|
||||||
|
</h6>
|
||||||
<br />
|
<br />
|
||||||
<div>
|
<div>
|
||||||
<div class="row q-col-gutter-md">
|
<div class="row q-col-gutter-md">
|
||||||
|
|
@ -10,7 +12,9 @@
|
||||||
filled
|
filled
|
||||||
type="text"
|
type="text"
|
||||||
v-model="formData.lnbits_site_title"
|
v-model="formData.lnbits_site_title"
|
||||||
:label="$t('ui_site_title') + $t('ui_changing_remove_lnbits_elements')"
|
:label="
|
||||||
|
$t('ui_site_title') + $t('ui_changing_remove_lnbits_elements')
|
||||||
|
"
|
||||||
></q-input>
|
></q-input>
|
||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -28,13 +32,19 @@
|
||||||
<q-toggle
|
<q-toggle
|
||||||
:tip="$t('ui_toggle_elements_tip')"
|
:tip="$t('ui_toggle_elements_tip')"
|
||||||
v-model="formData.lnbits_show_home_page_elements"
|
v-model="formData.lnbits_show_home_page_elements"
|
||||||
:label="formData.lnbits_show_home_page_elements ? $t('ui_elements_enable') : $t('ui_elements_disable')"
|
:label="
|
||||||
|
formData.lnbits_show_home_page_elements
|
||||||
|
? $t('ui_elements_enable')
|
||||||
|
: $t('ui_elements_disable')
|
||||||
|
"
|
||||||
></q-toggle>
|
></q-toggle>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p><span v-text="$t('ui_site_description')"></span></p>
|
<p>
|
||||||
|
<span v-text="$t('ui_site_description')"></span>
|
||||||
|
</p>
|
||||||
<q-input
|
<q-input
|
||||||
v-model="formData.lnbits_site_description"
|
v-model="formData.lnbits_site_description"
|
||||||
filled
|
filled
|
||||||
|
|
@ -45,7 +55,9 @@
|
||||||
<br />
|
<br />
|
||||||
<div class="row q-col-gutter-md">
|
<div class="row q-col-gutter-md">
|
||||||
<div class="col-12 col-md-4">
|
<div class="col-12 col-md-4">
|
||||||
<p><span v-text="$t('ui_default_wallet_name')"></span></p>
|
<p>
|
||||||
|
<span v-text="$t('ui_default_wallet_name')"></span>
|
||||||
|
</p>
|
||||||
<q-input
|
<q-input
|
||||||
filled
|
filled
|
||||||
type="text"
|
type="text"
|
||||||
|
|
@ -151,7 +163,11 @@
|
||||||
</q-input>
|
</q-input>
|
||||||
<q-toggle
|
<q-toggle
|
||||||
v-model="formData.lnbits_ad_space_enabled"
|
v-model="formData.lnbits_ad_space_enabled"
|
||||||
:label="formData.lnbits_ad_space_enabled ? $t('ads_enabled') : $t('ads_disabled')"
|
:label="
|
||||||
|
formData.lnbits_ad_space_enabled
|
||||||
|
? $t('ads_enabled')
|
||||||
|
: $t('ads_disabled')
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -207,4 +223,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-tab-panel>
|
</template>
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<q-tab-panel name="users">
|
<template id="lnbits-admin-users">
|
||||||
<q-card-section class="q-pa-none">
|
<q-card-section class="q-pa-none">
|
||||||
<h6 class="q-my-none q-mb-sm">
|
<h6 class="q-my-none q-mb-sm">
|
||||||
<span v-text="$t('user_management')"></span>
|
<span v-text="$t('user_management')"></span>
|
||||||
|
|
@ -80,4 +80,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-tab-panel>
|
</template>
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
{% include('pages/payments.vue') %} {% include('pages/node.vue') %} {%
|
{% include('pages/payments.vue') %} {% include('pages/node.vue') %} {%
|
||||||
include('pages/audit.vue') %} {% include('pages/wallets.vue') %} {%
|
include('pages/audit.vue') %} {% include('pages/wallets.vue') %} {%
|
||||||
include('pages/users.vue') %}
|
include('pages/users.vue') %} {% include('pages/admin.vue') %}
|
||||||
|
|
|
||||||
247
lnbits/templates/pages/admin.vue
Normal file
247
lnbits/templates/pages/admin.vue
Normal file
|
|
@ -0,0 +1,247 @@
|
||||||
|
<template id="page-admin">
|
||||||
|
<div class="row q-col-gutter-md q-mb-md">
|
||||||
|
<div class="col-12">
|
||||||
|
<q-card>
|
||||||
|
<div class="q-pa-sm">
|
||||||
|
<div class="row items-center justify-between q-gutter-xs">
|
||||||
|
<div class="col">
|
||||||
|
<q-btn
|
||||||
|
:label="$t('save')"
|
||||||
|
color="primary"
|
||||||
|
@click="updateSettings"
|
||||||
|
:disabled="!checkChanges"
|
||||||
|
>
|
||||||
|
<q-tooltip v-if="checkChanges">
|
||||||
|
<span v-text="$t('save_tooltip')"></span>
|
||||||
|
</q-tooltip>
|
||||||
|
|
||||||
|
<q-badge
|
||||||
|
v-if="checkChanges"
|
||||||
|
color="red"
|
||||||
|
rounded
|
||||||
|
floating
|
||||||
|
style="padding: 6px; border-radius: 6px"
|
||||||
|
/>
|
||||||
|
</q-btn>
|
||||||
|
|
||||||
|
<q-btn
|
||||||
|
v-if="isSuperUser"
|
||||||
|
:label="$t('restart')"
|
||||||
|
color="primary"
|
||||||
|
@click="restartServer"
|
||||||
|
class="q-ml-md"
|
||||||
|
>
|
||||||
|
<q-tooltip v-if="needsRestart">
|
||||||
|
<span v-text="$t('restart_tooltip')"></span>
|
||||||
|
</q-tooltip>
|
||||||
|
|
||||||
|
<q-badge
|
||||||
|
v-if="needsRestart"
|
||||||
|
color="red"
|
||||||
|
rounded
|
||||||
|
floating
|
||||||
|
style="padding: 6px; border-radius: 6px"
|
||||||
|
/>
|
||||||
|
</q-btn>
|
||||||
|
|
||||||
|
<q-btn
|
||||||
|
:label="$t('download_backup')"
|
||||||
|
flat
|
||||||
|
@click="downloadBackup"
|
||||||
|
></q-btn>
|
||||||
|
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
v-if="isSuperUser"
|
||||||
|
:label="$t('reset_defaults')"
|
||||||
|
color="primary"
|
||||||
|
@click="deleteSettings"
|
||||||
|
class="float-right"
|
||||||
|
>
|
||||||
|
<q-tooltip>
|
||||||
|
<span v-text="$t('reset_defaults_tooltip')"></span>
|
||||||
|
</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row q-col-gutter-md justify-center">
|
||||||
|
<div class="col q-gutter-y-md">
|
||||||
|
<q-card>
|
||||||
|
<q-tabs
|
||||||
|
v-if="$q.screen.lt.md"
|
||||||
|
v-model="tab"
|
||||||
|
dense
|
||||||
|
active-color="primary"
|
||||||
|
inline-label
|
||||||
|
class="text-primary"
|
||||||
|
>
|
||||||
|
<q-tab name="funding" icon="account_balance_wallet" label="Fund" />
|
||||||
|
<q-tab name="security" icon="security" label="Sec" />
|
||||||
|
<q-tab name="server" icon="settings" label="Srv" />
|
||||||
|
<q-tab name="exchange_providers" icon="swap_horiz" label="Exch" />
|
||||||
|
<q-tab name="fiat_providers" icon="account_balance" label="Fiat" />
|
||||||
|
<q-tab name="extensions" icon="extension" label="Ext" />
|
||||||
|
<q-tab name="notifications" icon="notifications" label="Not" />
|
||||||
|
<q-tab name="audit" icon="receipt_long" label="Aud" />
|
||||||
|
<q-tab name="site_customisation" icon="language" label="Site" />
|
||||||
|
<q-tab name="library" icon="image" label="Lib" />
|
||||||
|
</q-tabs>
|
||||||
|
|
||||||
|
<q-splitter>
|
||||||
|
<template v-slot:before>
|
||||||
|
<q-tabs v-model="tab" vertical active-color="primary">
|
||||||
|
<q-tab
|
||||||
|
name="funding"
|
||||||
|
icon="account_balance_wallet"
|
||||||
|
:label="$q.screen.gt.sm ? $t('funding') : null"
|
||||||
|
@update="val => (tab = val.name)"
|
||||||
|
><q-tooltip v-if="!$q.screen.gt.sm"
|
||||||
|
><span v-text="$t('funding')"></span></q-tooltip
|
||||||
|
></q-tab>
|
||||||
|
<q-tab
|
||||||
|
name="security"
|
||||||
|
icon="security"
|
||||||
|
:label="$q.screen.gt.sm ? $t('security') : null"
|
||||||
|
@update="val => (tab = val.name)"
|
||||||
|
><q-tooltip v-if="!$q.screen.gt.sm"
|
||||||
|
><span v-text="$t('security')"></span></q-tooltip
|
||||||
|
></q-tab>
|
||||||
|
<q-tab
|
||||||
|
name="server"
|
||||||
|
icon="price_change"
|
||||||
|
:label="$q.screen.gt.sm ? $t('payments') : null"
|
||||||
|
@update="val => (tab = val.name)"
|
||||||
|
><q-tooltip v-if="!$q.screen.gt.sm"
|
||||||
|
><span v-text="$t('payments')"></span></q-tooltip
|
||||||
|
></q-tab>
|
||||||
|
<q-tab
|
||||||
|
name="exchange_providers"
|
||||||
|
icon="show_chart"
|
||||||
|
:label="$q.screen.gt.sm ? $t('exchanges') : null"
|
||||||
|
><q-tooltip v-if="!$q.screen.gt.sm"
|
||||||
|
><span v-text="$t('exchanges')"></span></q-tooltip
|
||||||
|
></q-tab>
|
||||||
|
<q-tab
|
||||||
|
name="fiat_providers"
|
||||||
|
icon="credit_score"
|
||||||
|
:label="$q.screen.gt.sm ? $t('fiat_providers') : null"
|
||||||
|
><q-tooltip v-if="!$q.screen.gt.sm"
|
||||||
|
><span v-text="$t('fiat_providers')"></span></q-tooltip
|
||||||
|
></q-tab>
|
||||||
|
<q-tab
|
||||||
|
name="users"
|
||||||
|
icon="group"
|
||||||
|
:label="$q.screen.gt.sm ? $t('users') : null"
|
||||||
|
@update="val => (tab = val.name)"
|
||||||
|
><q-tooltip v-if="!$q.screen.gt.sm"
|
||||||
|
><span v-text="$t('users')"></span></q-tooltip
|
||||||
|
></q-tab>
|
||||||
|
|
||||||
|
<q-tab
|
||||||
|
name="extensions"
|
||||||
|
icon="extension"
|
||||||
|
:label="$q.screen.gt.sm ? $t('extensions') : null"
|
||||||
|
@update="val => (tab = val.name)"
|
||||||
|
><q-tooltip v-if="!$q.screen.gt.sm"
|
||||||
|
><span v-text="$t('extensions')"></span></q-tooltip
|
||||||
|
></q-tab>
|
||||||
|
|
||||||
|
<q-tab
|
||||||
|
name="notifications"
|
||||||
|
icon="notifications"
|
||||||
|
:label="$q.screen.gt.sm ? $t('notifications') : null"
|
||||||
|
@update="val => (tab = val.name)"
|
||||||
|
><q-tooltip v-if="!$q.screen.gt.sm"
|
||||||
|
><span v-text="$t('notifications')"></span></q-tooltip
|
||||||
|
></q-tab>
|
||||||
|
<q-tab
|
||||||
|
name="audit"
|
||||||
|
icon="playlist_add_check_circle"
|
||||||
|
:label="$q.screen.gt.sm ? $t('audit') : null"
|
||||||
|
@update="val => (tab = val.name)"
|
||||||
|
><q-tooltip v-if="!$q.screen.gt.sm"
|
||||||
|
><span v-text="$t('audit')"></span></q-tooltip
|
||||||
|
></q-tab>
|
||||||
|
<q-tab
|
||||||
|
name="library"
|
||||||
|
icon="image"
|
||||||
|
:label="$q.screen.gt.sm ? $t('library') : null"
|
||||||
|
@update="val => (tab = val.name)"
|
||||||
|
><q-tooltip v-if="!$q.screen.gt.sm"
|
||||||
|
><span v-text="$t('library')"></span></q-tooltip
|
||||||
|
></q-tab>
|
||||||
|
<q-tab
|
||||||
|
style="word-break: break-all"
|
||||||
|
name="site_customisation"
|
||||||
|
icon="language"
|
||||||
|
:label="$q.screen.gt.sm ? $t('site_customisation') : null"
|
||||||
|
@update="val => (tab = val.name)"
|
||||||
|
><q-tooltip v-if="!$q.screen.gt.sm"
|
||||||
|
><span v-text="$t('site_customisation')"></span></q-tooltip
|
||||||
|
></q-tab>
|
||||||
|
</q-tabs>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:after>
|
||||||
|
<q-form name="settings_form" id="settings_form">
|
||||||
|
<q-scroll-area style="height: 100vh">
|
||||||
|
<q-tab-panels
|
||||||
|
v-model="tab"
|
||||||
|
animated
|
||||||
|
vertical
|
||||||
|
scroll
|
||||||
|
transition-prev="jump-up"
|
||||||
|
transition-next="jump-up"
|
||||||
|
>
|
||||||
|
<q-tab-panel name="funding">
|
||||||
|
<lnbits-admin-funding
|
||||||
|
:is-super-user="isSuperUser"
|
||||||
|
:settings="settings"
|
||||||
|
:form-data="formData"
|
||||||
|
></lnbits-admin-funding>
|
||||||
|
</q-tab-panel>
|
||||||
|
<q-tab-panel name="fiat_providers">
|
||||||
|
<lnbits-admin-fiat-providers :form-data="formData" />
|
||||||
|
</q-tab-panel>
|
||||||
|
<q-tab-panel name="users">
|
||||||
|
<lnbits-admin-users :form-data="formData" />
|
||||||
|
</q-tab-panel>
|
||||||
|
<q-tab-panel name="server">
|
||||||
|
<lnbits-admin-server :form-data="formData" />
|
||||||
|
</q-tab-panel>
|
||||||
|
<q-tab-panel name="exchange_providers">
|
||||||
|
<lnbits-admin-exchange-providers :form-data="formData" />
|
||||||
|
</q-tab-panel>
|
||||||
|
<q-tab-panel name="extensions">
|
||||||
|
<lnbits-admin-extensions :form-data="formData" />
|
||||||
|
</q-tab-panel>
|
||||||
|
<q-tab-panel name="notifications">
|
||||||
|
<lnbits-admin-notifications :form-data="formData" />
|
||||||
|
</q-tab-panel>
|
||||||
|
<q-tab-panel name="security">
|
||||||
|
<lnbits-admin-security :form-data="formData" />
|
||||||
|
</q-tab-panel>
|
||||||
|
<q-tab-panel name="site_customisation">
|
||||||
|
<lnbits-admin-site-customisation :form-data="formData" />
|
||||||
|
</q-tab-panel>
|
||||||
|
<q-tab-panel name="audit">
|
||||||
|
<lnbits-admin-audit :form-data="formData" />
|
||||||
|
</q-tab-panel>
|
||||||
|
<q-tab-panel name="library">
|
||||||
|
<lnbits-admin-library :form-data="formData" />
|
||||||
|
</q-tab-panel>
|
||||||
|
</q-tab-panels>
|
||||||
|
</q-scroll-area>
|
||||||
|
</q-form>
|
||||||
|
</template>
|
||||||
|
</q-splitter>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
14
package.json
14
package.json
|
|
@ -101,9 +101,21 @@
|
||||||
"js/pages/audit.js",
|
"js/pages/audit.js",
|
||||||
"js/pages/wallets.js",
|
"js/pages/wallets.js",
|
||||||
"js/pages/users.js",
|
"js/pages/users.js",
|
||||||
|
"js/pages/admin.js",
|
||||||
|
"js/components/admin/lnbits-admin-funding.js",
|
||||||
|
"js/components/admin/lnbits-admin-funding-sources.js",
|
||||||
|
"js/components/admin/lnbits-admin-fiat-providers.js",
|
||||||
|
"js/components/admin/lnbits-admin-exchange-providers.js",
|
||||||
|
"js/components/admin/lnbits-admin-security.js",
|
||||||
|
"js/components/admin/lnbits-admin-users.js",
|
||||||
|
"js/components/admin/lnbits-admin-server.js",
|
||||||
|
"js/components/admin/lnbits-admin-extensions.js",
|
||||||
|
"js/components/admin/lnbits-admin-notifications.js",
|
||||||
|
"js/components/admin/lnbits-admin-site-customisation.js",
|
||||||
|
"js/components/admin/lnbits-admin-library.js",
|
||||||
|
"js/components/admin/lnbits-admin-audit.js",
|
||||||
"js/components/lnbits-qrcode.js",
|
"js/components/lnbits-qrcode.js",
|
||||||
"js/components/lnbits-qrcode-lnurl.js",
|
"js/components/lnbits-qrcode-lnurl.js",
|
||||||
"js/components/lnbits-funding-sources.js",
|
|
||||||
"js/components/extension-settings.js",
|
"js/components/extension-settings.js",
|
||||||
"js/components/data-fields.js",
|
"js/components/data-fields.js",
|
||||||
"js/components/payment-list.js",
|
"js/components/payment-list.js",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue