refactor: move /admin into vue component (#3466)

This commit is contained in:
dni ⚡
2025-11-07 18:10:59 +01:00
committed by GitHub
parent 2fecec2623
commit a40306f5cd
39 changed files with 1444 additions and 1235 deletions
+239
View File
@@ -0,0 +1,239 @@
<template id="lnbits-admin-audit">
<q-card-section class="q-pa-none">
<h6 class="q-my-none q-mb-sm">Audit</h6>
<div class="row q-mb-lg">
<div class="col-md-6 col-sm-12 q-pr-sm">
<q-item tag="label" v-ripple>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_audit_enabled"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
<q-item-section>
<q-item-label v-text="$t('enable_audit')"></q-item-label>
<q-item-label caption v-text="$t('audit_desc')"></q-item-label>
</q-item-section>
</q-item>
</div>
<div class="col-md-6 col-sm-12">
<q-input
filled
v-model="formData.lnbits_audit_retention_days"
type="number"
label="Retention days"
hint="Number of days to keep the audit entry."
>
</q-input>
</div>
</div>
<q-separator class="q-mb-lg q-mt-sm"></q-separator>
<div class="row">
<div class="col-md-3 col-sm-12 q-pr-sm">
<q-item tag="label" v-ripple>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_audit_log_request_body"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
<q-item-section>
<q-item-label v-text="$t('audit_record_req')"></q-item-label>
<q-item-label caption>
<span v-text="$t('audit_record_warning')"></span>
<br />
<ul>
<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>
<br />
<span v-text="$t('audit_record_use')"></span>
</q-item-label>
</q-item-section>
</q-item>
</div>
<div class="col-md-3 col-sm-12 q-pr-sm">
<q-item tag="label" v-ripple>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_audit_log_ip_address"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
<q-item-section>
<q-item-label>
<span v-text="$t('audit_ip')"></span>
</q-item-label>
<q-item-label caption>
<span v-text="$t('audit_ip_desc')"></span>
</q-item-label>
</q-item-section>
</q-item>
</div>
<div class="col-md-3 col-sm-12 q-pr-sm">
<q-item tag="label" v-ripple>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_audit_log_path_params"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
<q-item-section>
<q-item-label>
<span v-text="$t('audit_path_params')"></span>
</q-item-label>
<q-item-label caption>
<span v-text="$t('recommended')"></span>
</q-item-label>
</q-item-section>
</q-item>
</div>
<div class="col-md-3 col-sm-12 q-pr-sm">
<q-item tag="label" v-ripple>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_audit_log_query_params"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
<q-item-section>
<q-item-label>
<span v-text="$t('audit_query_params')"></span>
</q-item-label>
<q-item-label caption>
<span v-text="$t('recommended')"></span>
</q-item-label>
</q-item-section>
</q-item>
</div>
</div>
<q-separator class="q-mb-xl q-mt-sm"></q-separator>
<div class="row q-mb-lg">
<div class="col-md-6 col-sm-12 q-pr-sm">
<p><span v-text="$t('audit_http_methods')"></span></p>
<q-select
filled
v-model="formData.lnbits_audit_http_methods"
multiple
:hint="$t('audit_http_methods_hint')"
:label="$t('audit_http_methods_label')"
:options="[
'GET',
'POST',
'PUT',
'PATCH',
'DELETE',
'HEAD',
'OPTIONS'
]"
></q-select>
</div>
<div class="col-md-6 col-sm-12 q-pr-sm">
<p><span v-text="$t('audit_resp_codes')"></span></p>
<q-input
class="q-mb-md"
filled
v-model="formAddIncludeResponseCode"
@keydown.enter="addIncludeResponseCode"
type="text"
:label="$t('audit_resp_codes_label')"
:hint="$t('audit_resp_codes_hint')"
>
<q-btn @click="addIncludeResponseCode" dense flat icon="add"></q-btn>
</q-input>
<div>
<q-chip
v-for="code in formData.lnbits_audit_http_response_codes"
:key="code"
removable
@remove="removeIncludeResponseCode(code)"
color="primary"
text-color="white"
:label="code"
>
</q-chip>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-sm-12 q-pr-sm">
<p><span v-text="$t('audit_paths')"></span></p>
<q-input
class="q-mb-md"
filled
v-model="formAddIncludePath"
@keydown.enter="addIncludePath"
type="text"
:label="$t('audit_paths_label')"
:hint="$t('audit_paths_hint')"
>
<q-btn @click="addIncludePath" dense flat icon="add"></q-btn>
</q-input>
<div>
<q-chip
v-for="path in formData.lnbits_audit_include_paths"
:key="path"
removable
@remove="removeIncludePath(path)"
color="primary"
text-color="white"
:label="path"
>
</q-chip>
</div>
<br />
</div>
<div class="col-md-6 col-sm-12">
<p>
<span v-text="$t('audit_paths_exclude')"></span>
</p>
<q-input
class="q-mb-md"
filled
v-model="formAddExcludePath"
@keydown.enter="addExcludePath"
type="text"
:label="$t('audit_paths_exclude_label')"
:hint="$t('audit_paths_exclude_hint')"
>
<q-btn @click="addExcludePath" dense flat icon="add"></q-btn>
</q-input>
<div>
<q-chip
v-for="path in formData.lnbits_audit_exclude_paths"
:key="path"
removable
@remove="removeExcludePath(path)"
color="primary"
text-color="white"
:label="path"
>
</q-chip>
</div>
<br />
<br />
</div>
</div>
</q-card-section>
</template>
@@ -0,0 +1,244 @@
<template id="lnbits-admin-exchange-providers">
<h6 class="q-my-none q-mb-sm">
<span v-text="$t('exchange_providers')"></span>
</h6>
<div class="row">
<div class="col-12 col-md-8">
<div class="q-pa-sm">
<canvas
style="
width: 100% !important;
height: auto !important;
min-height: 350px;
max-height: 50vh;
"
ref="exchangeRatesChart"
></canvas>
</div>
</div>
<div class="col-12 col-md-4">
<q-input
filled
v-model="formData.lnbits_exchange_history_refresh_interval_seconds"
type="number"
label="Refresh Interval (seconds)"
hint="How often should the exchange rates be fetched. Set to zero to disable."
>
</q-input>
<q-input
filled
v-model="formData.lnbits_exchange_history_size"
type="number"
label="History Size"
hint="How many data points should be kept in memory."
>
</q-input>
<ul>
<li>
<code>Refresh Interval</code> and <code> History Size </code>are for
historical purposes only.
</li>
<li>These two settings do not affect the live price computation.</li>
<li>
Chart currency:
<strong
><span
v-text="formData.lnbits_default_accounting_currency || 'USD'"
></span
></strong>
</li>
</ul>
</div>
</div>
<div class="row q-mt-md">
<div class="col-6">
<q-btn
@click="addExchangeProvider()"
label="Add Exchange Provider"
color="primary"
class="q-mb-md"
>
</q-btn>
</div>
<div class="col-6">
<q-btn
@click="getDefaultSetting('lnbits_exchange_rate_providers')"
flat
:label="$t('reset_defaults')"
color="primary"
class="float-right"
>
</q-btn>
</div>
</div>
<div class="overflow-auto">
<q-table
row-key="name"
:rows="formData.lnbits_exchange_rate_providers"
:columns="exchangesTable.columns"
v-model:pagination="exchangesTable.pagination"
:grid="$q.screen.xs"
:dense="$q.screen.lt.md"
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th auto-width></q-th>
<q-th v-for="col in props.cols" :key="col.name" :props="props">
<span v-text="col.label"></span>
</q-th>
</q-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props">
<q-td>
<q-btn
@click="removeExchangeProvider(props.row)"
round
icon="delete"
size="sm"
color="negative"
class="q-ml-xs"
>
</q-btn>
</q-td>
<q-td>
<q-input
dense
filled
v-model="props.row.name"
@update:model-value="formData.touch = null"
type="text"
>
</q-input>
</q-td>
<q-td full-width>
<q-input
dense
filled
v-model="props.row.api_url"
@update:model-value="formData.touch = null"
type="text"
>
</q-input
></q-td>
<q-td>
<q-input
dense
filled
v-model="props.row.path"
@update:model-value="formData.touch = null"
type="text"
>
</q-input>
</q-td>
<q-td>
<q-select
filled
dense
v-model="props.row.exclude_to"
@update:model-value="formData.touch = null"
multiple
:options="currencies"
></q-select>
</q-td>
<q-td>
<q-btn
@click="showTickerConversionDialog(props.row)"
round
icon="add"
size="sm"
color="gray"
class="q-ml-xs"
>
</q-btn>
<q-chip
v-for="(ticker, index) in props.row.ticker_conversion"
:key="ticker"
removable
dense
filled
@remove="removeExchangeTickerConversion(props.row, ticker)"
color="primary"
text-color="white"
:label="ticker"
class="ellipsis"
>
</q-chip>
</q-td>
</q-tr>
</template>
</q-table>
</div>
<ul>
<li>
<code>API URL</code> and <code>JSON Path</code> fields can use the
<code>{to}</code> and <code>{TO}</code> placeholders for the code of the
currency
</li>
<li>
<code>{TO}</code> is the uppercase code and <code>{to}</code> is the
lowercase code
</li>
</ul>
<q-separator class="q-ma-md"></q-separator>
<div class="row">
<div class="col-md-4 col-sm-12">
<q-input
filled
v-model="formData.lnbits_exchange_rate_cache_seconds"
type="number"
label="Exchange rate cache (seconds)"
hint="For how many seconds should the exchange rate be cached."
>
</q-input>
</div>
<div class="col-md-8 col-sm-12"></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"
></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>
@@ -0,0 +1,143 @@
<template id="lnbits-admin-extensions">
<q-card-section class="q-pa-none">
<div>
<h6 class="q-my-none">
<span v-text="$t('extensions')"></span>
</h6>
<div class="row q-col-gutter-md">
<div class="col-12 q-mb-md">
<p>
<span v-text="$t('extension_sources')"></span>
</p>
<q-input
class="q-mb-md"
filled
v-model="formAddExtensionsManifest"
@keydown.enter="addExtensionsManifest"
type="text"
:label="$t('ext_sources_label')"
:hint="$t('ext_sources_hint')"
>
<q-btn @click="addExtensionsManifest" dense flat icon="add"></q-btn>
</q-input>
<div>
<q-chip
v-for="manifestUrl in formData.lnbits_extensions_manifests"
:key="manifestUrl"
removable
@remove="removeExtensionsManifest(manifestUrl)"
color="primary"
text-color="white"
><span class="ellipsis" v-text="manifestUrl"></span
></q-chip>
</div>
</div>
</div>
<div class="row q-col-gutter-md">
<div class="col-12 col-md-6">
<p>
<span v-text="$t('admin_extensions')"></span>
</p>
<q-select
filled
v-model="formData.lnbits_admin_extensions"
multiple
:label="$t('admin_extensions_label')"
:hint="$t('admin_extensions_hint')"
:options="g.extensions"
></q-select>
</div>
<div class="col-12 col-md-6">
<p>
<span v-text="$t('user_default_extensions')"></span>
</p>
<q-select
filled
v-model="formData.lnbits_user_default_extensions"
multiple
:label="$t('user_default_extensions_label')"
:hint="$t('user_default_extensions_hint')"
:options="g.extensions"
></q-select>
</div>
<div class="col-12 col-md-6">
<p>
<span v-text="$t('miscellaneous')"></span>
</p>
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label>
<span v-text="$t('misc_disable_extensions')"></span>
</q-item-label>
<q-item-label caption>
<span v-text="$t('misc_disable_extensions_label')"></span>
</q-item-label>
</q-item-section>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_extensions_deactivate_all"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
</q-item>
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label>
<span v-text="$t('misc_disable_extensions_builder')"></span>
</q-item-label>
<q-item-label caption>
<span
v-text="$t('misc_disable_extensions_builder_label')"
></span>
</q-item-label>
</q-item-section>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_extensions_builder_activate_non_admins"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
</q-item>
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label>
<span v-text="$t('misc_hide_api')"></span>
</q-item-label>
<q-item-label caption>
<span v-text="$t('misc_hide_api_label')"></span>
</q-item-label>
</q-item-section>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_hide_api"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
</q-item>
<br />
</div>
<div class="col-12 col-md-6">
<p>
<span v-text="$t('extension_builder_manifest_url')"></span>
</p>
<q-input
filled
v-model="formData.lnbits_extensions_builder_manifest_url"
:label="$t('extension_builder_manifest_url')"
:hint="$t('extension_builder_manifest_url_hint')"
></q-input>
</div>
</div>
</div>
</q-card-section>
</template>
@@ -0,0 +1,300 @@
<template id="lnbits-admin-fiat-providers">
<h6 class="q-my-none q-mb-sm">
<span v-text="$t('fiat_providers')"></span>
<q-btn
round
flat
@click="hideInputToggle = !hideInputToggle"
:icon="hideInputToggle ? 'visibility_off' : 'visibility'"
></q-btn>
</h6>
<div class="row">
<div class="col">
<q-list bordered class="rounded-borders">
<q-expansion-item header-class="text-primary text-bold">
<template v-slot:header>
<q-item-section avatar>
<q-avatar>
<img src="/static/images/stripe_logo.ico" />
</q-avatar>
</q-item-section>
<q-item-section> Stripe </q-item-section>
<q-item-section side>
<div class="row items-center">
<q-toggle
size="md"
:label="$t('enabled')"
v-model="formData.stripe_enabled"
color="green"
unchecked-icon="clear"
/>
</div>
</q-item-section>
</template>
<q-card class="q-pb-xl">
<q-expansion-item :label="$t('api')" default-opened>
<q-card-section class="q-pa-md">
<q-input
filled
type="text"
v-model="formData.stripe_api_endpoint"
:label="$t('endpoint')"
></q-input>
<q-input
filled
class="q-mt-md"
:type="hideInputToggle ? 'password' : 'text'"
v-model="formData.stripe_api_secret_key"
:label="$t('secret_key')"
></q-input>
<q-input
filled
class="q-mt-md"
type="text"
v-model="formData.stripe_payment_success_url"
:label="$t('callback_success_url')"
:hint="$t('callback_success_url_hint')"
></q-input>
</q-card-section>
<q-card-section class="q-pa-md">
<div class="row">
<div class="col">
<q-btn
outline
color="grey"
class="float-right"
:label="$t('check_connection')"
@click="checkFiatProvider('stripe')"
></q-btn>
</div>
</div>
</q-card-section>
</q-expansion-item>
<q-expansion-item :label="$t('webhook')" default-opened>
<q-card-section>
<span v-text="$t('webhook_stripe_description')"></span>
</q-card-section>
<q-card-section>
<q-input
filled
class="q-mt-md"
type="text"
disable
v-model="formData.stripe_payment_webhook_url"
:label="$t('webhook_url')"
:hint="$t('webhook_url_hint')"
></q-input>
<q-input
filled
class="q-mt-md"
:type="hideInputToggle ? 'password' : 'text'"
v-model="formData.stripe_webhook_signing_secret"
:label="$t('signing_secret')"
:hint="$t('signing_secret_hint')"
></q-input>
</q-card-section>
<q-card-section>
<span v-text="$t('webhook_events_list')"></span>
<ul>
<li>
<code>checkout.session.completed</code>
</li>
- the user completed the checkout process
<li><code>invoice.paid</code></li>
- the invoice was successfully paid (for subscriptions)
</ul>
</q-card-section>
</q-expansion-item>
<q-expansion-item :label="$t('service_fee')">
<q-card-section>
<div class="row">
<div class="col-md-4 col-sm-12">
<q-input
filled
class="q-ma-sm"
type="number"
min="0"
v-model="formData.stripe_limits.service_fee_percent"
@update:model-value="formData.touch = null"
:label="$t('service_fee_label')"
:hint="$t('service_fee_hint')"
></q-input>
</div>
<div class="col-md-4 col-sm-12">
<q-input
filled
class="q-ma-sm"
type="number"
min="0"
v-model="formData.stripe_limits.service_max_fee_sats"
@update:model-value="formData.touch = null"
:label="$t('service_fee_max')"
:hint="$t('service_fee_max_hint')"
></q-input>
</div>
<div class="col-md-4 col-sm-12">
<q-input
filled
class="q-ma-sm"
type="text"
v-model="formData.stripe_limits.service_fee_wallet_id"
@update:model-value="formData.touch = null"
:label="$t('fee_wallet_label')"
:hint="$t('fee_wallet_hint')"
></q-input>
</div>
</div>
</q-card-section>
</q-expansion-item>
<q-expansion-item :label="$t('amount_limits')">
<q-card-section>
<div class="row">
<div class="col-md-4 col-sm-12">
<q-input
filled
class="q-ma-sm"
type="number"
min="0"
v-model="formData.stripe_limits.service_min_amount_sats"
@update:model-value="formData.touch = null"
:label="$t('min_incoming_payment_amount')"
:hint="$t('min_incoming_payment_amount_desc')"
></q-input>
</div>
<div class="col-md-4 col-sm-12">
<q-input
filled
class="q-ma-sm"
type="number"
min="0"
v-model="formData.stripe_limits.service_max_amount_sats"
@update:model-value="formData.touch = null"
:label="$t('max_incoming_payment_amount')"
:hint="$t('max_incoming_payment_amount_desc')"
></q-input>
</div>
<div class="col-md-4 col-sm-12">
<q-input
filled
class="q-ma-sm"
v-model="formData.stripe_limits.service_faucet_wallet_id"
@update:model-value="formData.touch = null"
:label="$t('faucest_wallet_id')"
:hint="$t('faucest_wallet_id_hint')"
></q-input>
</div>
</div>
<q-item>
<q-item-section>
<q-item-label v-text="$t('faucest_wallet')"></q-item-label>
<q-item-label caption>
<ul>
<li>
<span
v-text="
$t('faucest_wallet_desc_1', {
provider: 'stripe'
})
"
></span>
</li>
<li>
<span
v-text="
$t('faucest_wallet_desc_2', {
provider: 'stripe'
})
"
></span>
</li>
<li>
<span v-text="$t('faucest_wallet_desc_3')"></span>
</li>
<li>
<span
v-text="
$t('faucest_wallet_desc_4', {
provider: 'stripe'
})
"
></span>
</li>
<li>
<span v-text="$t('faucest_wallet_desc_5')"></span>
</li>
</ul>
<br />
</q-item-label>
</q-item-section>
</q-item>
</q-card-section>
</q-expansion-item>
<q-expansion-item :label="$t('allowed_users')">
<q-card-section>
<q-input
filled
v-model="formAddStripeUser"
@keydown.enter="addStripeAllowedUser"
type="text"
:label="$t('allowed_users_label')"
:hint="
$t('allowed_users_hint_feature', {
feature: 'Stripe'
})
"
>
<q-btn
@click="addStripeAllowedUser"
dense
flat
icon="add"
></q-btn>
</q-input>
<div>
<q-chip
v-for="user in formData.stripe_limits.allowed_users"
@update:model-value="formData.touch = null"
:key="user"
removable
@remove="removeStripeAllowedUser(user)"
color="primary"
text-color="white"
:label="user"
class="ellipsis"
>
</q-chip>
</div>
</q-card-section>
</q-expansion-item>
</q-card>
</q-expansion-item>
<q-separator />
<q-expansion-item header-class="text-primary text-bold">
<template v-slot:header>
<q-item-section avatar>
<q-avatar>
<img src="/static/images/square_logo.png" />
</q-avatar>
</q-item-section>
<q-item-section> Square </q-item-section>
<q-item-section side>
<div class="row items-center">Disabled</div>
</q-item-section>
</template>
<q-card>
<q-card-section> Coming Soon </q-card-section>
</q-card>
</q-expansion-item>
</q-list>
</div>
</div>
</template>
@@ -0,0 +1,244 @@
<template id="lnbits-admin-funding">
<q-card-section class="q-pa-none">
<h6 class="q-my-none">
<span v-text="$t('wallets_management')"></span>
</h6>
<br />
<div>
<div class="row">
<div class="col">
<p>
<span v-text="$t('funding_source_info')"></span>
</p>
<ul>
<li
v-text="
$t('funding_source', {
wallet_class: settings.lnbits_backend_wallet_class
})
"
></li>
<li
v-text="
$t('node_balance', {
balance: (auditData.node_balance_sats || 0).toLocaleString()
})
"
></li>
<li
v-text="
$t('lnbits_balance', {
balance: (auditData.lnbits_balance_sats || 0).toLocaleString()
})
"
></li>
<li
v-text="
$t('funding_reserve_percent', {
percent:
auditData.lnbits_balance_sats > 0
? (
(auditData.node_balance_sats /
auditData.lnbits_balance_sats) *
100
).toFixed(2)
: 100
})
"
></li>
</ul>
<br />
</div>
<div class="col">
<div v-if="LNBITS_NODE_UI">
<p>
<span v-text="$t('node_management')"></span>
</p>
<q-toggle
:label="$t('toggle_node_ui')"
v-model="formData.lnbits_node_ui"
></q-toggle>
<q-toggle
v-if="formData.lnbits_node_ui"
:label="$t('toggle_public_node_ui')"
v-model="formData.lnbits_public_node_ui"
></q-toggle>
<br />
<q-toggle
v-if="formData.lnbits_node_ui"
:label="$t('toggle_transactions_node_ui')"
v-model="formData.lnbits_node_ui_transactions"
></q-toggle>
</div>
<p v-if="!LNBITS_NODE_UI">
<span v-text="$t('node_management_not_supported')"></span>
</p>
</div>
</div>
<div class="row q-col-gutter-md">
<div class="col-12 col-md-3">
<p><span v-text="$t('fee_reserve')"></span></p>
<q-input
type="number"
filled
v-model="formData.lnbits_reserve_fee_min"
:label="$t('fee_reserve_msats')"
>
</q-input>
</div>
<div class="col-12 col-md-3">
<p>
<span v-text="$t('fee_reserve_percent')"></span>
</p>
<q-input
type="number"
filled
name="lnbits_reserve_fee_percent"
v-model="formData.lnbits_reserve_fee_percent"
:label="$t('reserve_fee_in_percent')"
step="0.1"
></q-input>
</div>
<div class="col-12 col-md-3">
<p><span v-text="$t('invoice_expiry')"></span></p>
<q-input
filled
v-model.number="formData.lightning_invoice_expiry"
type="number"
:label="$t('invoice_expiry_label')"
mask="#######"
>
</q-input>
</div>
<div class="col-12 col-md-3">
<p>
<span v-text="$t('payment_wait_time')"></span>
</p>
<q-input
type="number"
filled
name="lnbits_funding_source_pay_invoice_wait_seconds"
v-model="formData.lnbits_funding_source_pay_invoice_wait_seconds"
:label="$t('payment_wait_time')"
:hint="$t('payment_wait_time_desc')"
step="1"
min="0"
></q-input>
</div>
</div>
<div v-if="isSuperUser">
<lnbits-admin-funding-sources
:form-data="formData"
:allowed-funding-sources="settings.lnbits_allowed_funding_sources"
/>
<div class="row q-col-gutter-md q-my-md">
<div class="col-12 col-sm-8">
<q-item tag="div">
<q-item-section>
<q-item-label
v-text="$t('funding_source_retries')"
></q-item-label>
<q-item-label
caption
v-text="$t('funding_source_retries_desc')"
></q-item-label>
</q-item-section>
<q-item-section>
<q-input
filled
v-model="formData.funding_source_max_retries"
type="number"
/>
</q-item-section>
</q-item>
</div>
</div>
</div>
<q-separator></q-separator>
<h6 class="q-mt-lg q-mb-sm">
<p v-text="$t('watchdog')"></p>
</h6>
<div class="row q-col-gutter-md">
<div class="col-12 col-md-6">
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label v-text="$t('enable_watchdog')"></q-item-label>
<q-item-label
caption
v-text="$t('enable_watchdog_desc')"
></q-item-label>
</q-item-section>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_watchdog_switch_to_voidwallet"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
</q-item>
</div>
<div class="col-12 col-md-6">
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notification_watchdog_limit')"
></q-item-label>
<q-item-label
caption
v-text="$t('notification_watchdog_limit_desc')"
></q-item-label>
</q-item-section>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_notification_watchdog"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
</q-item>
</div>
<div class="col-12 col-md-6">
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label v-text="$t('watchdog_interval')"></q-item-label>
<q-item-label
caption
v-text="$t('watchdog_interval_desc')"
></q-item-label>
</q-item-section>
<q-item-section>
<q-input
filled
v-model="formData.lnbits_watchdog_interval_minutes"
type="number"
/>
</q-item-section>
</q-item>
</div>
<div class="col-12 col-md-6">
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label v-text="$t('watchdog_delta')"></q-item-label>
<q-item-label
caption
v-text="$t('watchdog_delta_desc')"
></q-item-label>
</q-item-section>
<q-item-section>
<q-input
filled
v-model="formData.lnbits_watchdog_delta"
type="number"
/>
</q-item-section>
</q-item>
</div>
</div>
</div>
</q-card-section>
</template>
@@ -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>
@@ -0,0 +1,67 @@
<template id="lnbits-admin-library">
<q-card-section class="q-pa-none">
<h6 class="q-my-none q-mb-sm">
<span v-text="$t('image_library')"></span>
</h6>
<q-btn
color="primary"
label="Add Image"
@click="$refs.imageInput.click()"
class="q-mb-md"
/>
<input
type="file"
ref="imageInput"
accept="image/png, image/jpeg, image/gif"
style="display: none"
@change="onImageInput"
/>
</q-card-section>
<div class="row q-col-gutter-sm q-pa-sm">
<div
v-for="image in library_images"
:key="image.filename"
class="col-6 col-sm-4 col-md-3 col-lg-2"
style="max-width: 200px"
>
<q-card class="q-mb-sm">
<q-img :src="image.url" style="height: 150px" />
<q-card-section
class="q-pt-md q-pb-md row items-center justify-between"
>
<small
><div
class="text-caption ellipsis"
style="max-width: 100px"
:title="image.filename"
v-text="image.filename"
></div
></small>
<q-btn
dense
flat
size="sm"
icon="content_copy"
@click="copyText(image.url)"
:title="$t('copy')"
><q-tooltip>Copy image link</q-tooltip></q-btn
>
<q-btn
dense
flat
size="sm"
icon="delete"
color="negative"
@click="deleteImage(image.filename)"
:title="$t('delete')"
><q-tooltip>Delete image</q-tooltip></q-btn
>
</q-card-section>
</q-card>
</div>
</div>
<div v-if="library_images.length === 0" class="q-pa-xl">
<div class="text-subtitle2 text-grey">No images uploaded yet.</div>
</div>
</template>
@@ -0,0 +1,515 @@
<template id="lnbits-admin-notifications">
<q-card-section class="q-pa-none">
<h6 class="q-my-none q-mb-sm">
<span v-text="$t('notifications_configure')"></span>
<q-btn
round
flat
@click="hideInputsToggle()"
:icon="hideInputToggle ? 'visibility_off' : 'visibility'"
></q-btn>
</h6>
<q-separator class="q-mt-md q-mb-sm"></q-separator>
<div class="row q-col-gutter-md">
<div class="col-sm-12 col-md-6">
<strong v-text="$t('notifications_nostr_config')"></strong>
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notifications_enable_nostr')"
></q-item-label>
<q-item-label
caption
v-text="$t('notifications_enable_nostr_desc')"
></q-item-label>
</q-item-section>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_nostr_notifications_enabled"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
</q-item>
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notifications_nostr_private_key')"
></q-item-label>
<q-item-label
caption
v-text="$t('notifications_nostr_private_key_desc')"
></q-item-label>
</q-item-section>
<q-item-section>
<q-input
:type="hideInputToggle ? 'password' : 'text'"
filled
v-model="formData.lnbits_nostr_notifications_private_key"
/>
</q-item-section>
</q-item>
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notifications_nostr_identifiers')"
></q-item-label>
<q-item-label
caption
v-text="$t('notifications_nostr_identifiers_desc')"
></q-item-label>
</q-item-section>
<q-item-section>
<q-input
filled
v-model="nostrNotificationIdentifier"
@keydown.enter="addNostrNotificationIdentifier"
>
<q-btn
@click="addNostrNotificationIdentifier()"
dense
flat
icon="add"
></q-btn>
</q-input>
</q-item-section>
</q-item>
<div>
<q-chip
v-for="identifier in formData.lnbits_nostr_notifications_identifiers"
:key="identifier"
removable
@remove="removeNostrNotificationIdentifier(identifier)"
color="primary"
text-color="white"
class="ellipsis"
:label="identifier"
><q-tooltip
v-if="identifier"
anchor="top middle"
self="bottom middle"
><span v-text="identifier"></span></q-tooltip
></q-chip>
</div>
</div>
<div class="col-sm-12 col-md-6">
<strong v-text="$t('notifications_telegram_config')"></strong>
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notifications_enable_telegram')"
></q-item-label>
<q-item-label
caption
v-text="$t('notifications_enable_telegram_desc')"
></q-item-label>
</q-item-section>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_telegram_notifications_enabled"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
</q-item>
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notifications_telegram_access_token')"
></q-item-label>
<q-item-label
caption
v-text="$t('notifications_telegram_access_token_desc')"
></q-item-label>
</q-item-section>
<q-item-section>
<q-input
:type="hideInputToggle ? 'password' : 'text'"
filled
v-model="formData.lnbits_telegram_notifications_access_token"
/>
</q-item-section>
</q-item>
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label v-text="$t('notifications_chat_id')"></q-item-label>
<q-item-label
caption
v-text="$t('notifications_chat_id_desc')"
></q-item-label>
</q-item-section>
<q-item-section>
<q-input
filled
v-model="formData.lnbits_telegram_notifications_chat_id"
/>
</q-item-section>
</q-item>
</div>
<div class="col-sm-12">
<q-separator></q-separator>
</div>
<div class="col-12">
<strong v-text="$t('notifications_email_config')"></strong>
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notifications_enable_email')"
></q-item-label>
<q-item-label
caption
v-text="$t('notifications_enable_email_desc')"
></q-item-label>
</q-item-section>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_email_notifications_enabled"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
</q-item>
<div v-if="formData.lnbits_email_notifications_enabled" class="row">
<div class="col">
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notifications_send_email')"
></q-item-label>
<q-item-label
caption
v-text="$t('notifications_send_email_desc')"
></q-item-label>
</q-item-section>
<q-item-section>
<q-input
:type="hideInputToggle ? 'password' : 'text'"
filled
v-model="formData.lnbits_email_notifications_email"
/>
</q-item-section>
</q-item>
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notifications_send_email_username')"
></q-item-label>
<q-item-label
caption
v-text="$t('notifications_send_email_username_desc')"
></q-item-label>
</q-item-section>
<q-item-section>
<q-input
:type="hideInputToggle ? 'password' : 'text'"
filled
v-model="formData.lnbits_email_notifications_username"
/>
</q-item-section>
</q-item>
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notifications_send_email_password')"
></q-item-label>
<q-item-label
caption
v-text="$t('notifications_send_email_password_desc')"
></q-item-label>
</q-item-section>
<q-item-section>
<q-input
:type="hideInputToggle ? 'password' : 'text'"
filled
v-model="formData.lnbits_email_notifications_password"
/>
</q-item-section>
</q-item>
<q-item>
<q-btn
@click="sendTestEmail()"
:label="$t('notifications_send_test_email')"
color="primary"
class="q-mt-md"
></q-btn>
</q-item>
</div>
<div class="col">
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notifications_send_to_emails')"
></q-item-label>
<q-item-label
caption
v-text="$t('notifications_send_to_emails_desc')"
></q-item-label>
</q-item-section>
<q-item-section>
<q-input
filled
v-model="emailNotificationAddress"
@keydown.enter="addEmailNotificationAddress"
>
<q-btn
@click="addEmailNotificationAddress()"
dense
flat
icon="add"
></q-btn>
</q-input>
<div>
<q-chip
v-for="to_email in formData.lnbits_email_notifications_to_emails"
:key="to_email"
removable
@remove="removeEmailNotificationAddress(to_email)"
color="primary"
text-color="white"
><span class="ellipsis" v-text="to_email"></span
></q-chip>
</div>
</q-item-section>
</q-item>
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notifications_send_email_server_port')"
></q-item-label>
<q-item-label
caption
v-text="$t('notifications_send_email_server_port_desc')"
></q-item-label>
</q-item-section>
<q-item-section>
<q-input
:type="hideInputToggle ? 'password' : 'text'"
filled
v-model="formData.lnbits_email_notifications_port"
/>
</q-item-section>
</q-item>
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notifications_send_email_server')"
></q-item-label>
<q-item-label
caption
v-text="$t('notifications_send_email_server_desc')"
></q-item-label>
</q-item-section>
<q-item-section>
<q-input
:type="hideInputToggle ? 'password' : 'text'"
filled
v-model="formData.lnbits_email_notifications_server"
/>
</q-item-section>
</q-item>
</div>
</div>
</div>
</div>
<q-separator> </q-separator>
<h6 class="q-mb-sm">
<span v-text="$t('notifications')"></span>
</h6>
<div class="row q-col-gutter-md">
<div class="col-12">
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notification_settings_update')"
></q-item-label>
<q-item-label
caption
v-text="$t('notification_settings_update_desc')"
></q-item-label>
</q-item-section>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_notification_settings_update"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
</q-item>
</div>
<div class="col-12">
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notification_credit_debit')"
></q-item-label>
<q-item-label
caption
v-text="$t('notification_credit_debit_desc')"
></q-item-label>
</q-item-section>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_notification_credit_debit"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
</q-item>
</div>
<div class="col-12">
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notification_server_start_stop')"
></q-item-label>
<q-item-label
caption
v-text="$t('notification_server_start_stop_desc')"
></q-item-label>
</q-item-section>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_notification_server_start_stop"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
</q-item>
</div>
<div class="col-12">
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notification_balance_delta_changed')"
></q-item-label>
<q-item-label
caption
v-text="$t('notification_balance_delta_changed_desc')"
></q-item-label>
</q-item-section>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.notification_balance_delta_changed"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
</q-item>
</div>
<div class="col-12">
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notification_watchdog_limit')"
></q-item-label>
<q-item-label
caption
v-text="$t('notification_watchdog_limit_desc')"
></q-item-label>
</q-item-section>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_notification_watchdog"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
</q-item>
</div>
<div class="col-12">
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notification_server_status')"
></q-item-label>
<q-item-label
caption
v-text="$t('notification_server_status_desc')"
></q-item-label>
</q-item-section>
<q-item-section avatar>
<q-input
class="flow-right"
type="number"
min="0"
filled
v-model="formData.lnbits_notification_server_status_hours"
/>
</q-item-section>
</q-item>
</div>
<div class="col-12">
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notification_incoming_payment')"
></q-item-label>
<q-item-label
caption
v-text="$t('notification_incoming_payment_desc')"
></q-item-label>
</q-item-section>
<q-item-section avatar>
<q-input
class="flow-right"
type="number"
min="0"
filled
v-model="
formData.lnbits_notification_incoming_payment_amount_sats
"
/>
</q-item-section>
</q-item>
</div>
<div class="col-12">
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label
v-text="$t('notification_outgoing_payment')"
></q-item-label>
<q-item-label
caption
v-text="$t('notification_outgoing_payment_desc')"
></q-item-label>
</q-item-section>
<q-item-section avatar>
<q-input
class="flow-right"
type="number"
min="0"
filled
v-model="
formData.lnbits_notification_outgoing_payment_amount_sats
"
/>
</q-item-section>
</q-item>
</div>
</div>
</q-card-section>
</template>
@@ -0,0 +1,349 @@
<template id="lnbits-admin-security">
<q-card-section class="q-pa-none">
<h6 class="q-my-none">
<span v-text="$t('server_management')"></span>
</h6>
<div class="row">
<div class="col-12 col-md-6">
<p><span v-text="$t('base_url')"></span></p>
<q-input
filled
v-model.number="formData.lnbits_baseurl"
:label="$t('base_url_label')"
></q-input>
<br />
</div>
</div>
<h6 class="q-my-none q-mb-sm">
<span v-text="$t('authentication')"></span>
</h6>
<div class="row q-col-gutter-sm">
<div class="col-12 col-md-6">
<q-input
filled
v-model="formData.auth_token_expire_minutes"
type="number"
:label="$t('auth_token_expiry_label')"
:hint="$t('auth_token_expiry_hint')"
>
</q-input>
</div>
<div class="col-12 col-md-6">
<q-select
filled
v-model="formData.auth_allowed_methods"
multiple
:hint="$t('auth_allowed_methods_hint')"
:label="$t('auth_allowed_methods_label')"
:options="formData.auth_all_methods"
:option-label="
option =>
option.length > 25 ? option.substring(0, 22) + '...' : option
"
></q-select>
</div>
</div>
</q-card-section>
<q-card-section
v-if="formData.auth_allowed_methods?.includes('nostr-auth-nip98')"
class="q-pl-xl"
>
<strong class="q-my-none q-mb-sm">Nostr Auth</strong>
<div class="row">
<div class="col-12">
<q-input
class="q-mb-sm"
filled
v-model="nostrAcceptedUrl"
@keydown.enter="addNostrUrl"
type="text"
:label="$t('auth_nostr_label')"
:hint="$t('auth_nostr_hint')"
>
<q-btn @click="addNostrUrl" dense flat icon="add"></q-btn>
</q-input>
</div>
<div class="col-12">
<q-chip
v-for="url in formData.nostr_absolute_request_urls"
:key="url"
removable
@remove="removeNostrUrl(url)"
color="primary"
text-color="white"
:label="url"
class="ellipsis"
></q-chip>
</div>
</div>
</q-card-section>
<q-card-section
v-if="formData.auth_allowed_methods?.includes('google-auth')"
class="q-pl-xl"
>
<strong class="q-my-none q-mb-sm">Google Auth</strong>
<div class="row">
<div class="col-12 col-md-6 q-pr-sm">
<q-input
filled
v-model="formData.google_client_id"
:label="$t('auth_google_ci_label')"
:hint="$t('auth_google_ci_hint')"
>
</q-input>
</div>
<div class="col-12 col-md-6">
<q-input
filled
v-model="formData.google_client_secret"
type="password"
:label="$t('auth_google_cs_label')"
>
</q-input>
</div>
</div>
</q-card-section>
<q-card-section
v-if="formData.auth_allowed_methods?.includes('github-auth')"
class="q-pl-xl"
>
<strong class="q-my-none q-mb-sm">GitHub Auth</strong>
<div class="row">
<div class="col-12 col-md-6 q-pr-sm">
<q-input
filled
v-model="formData.github_client_id"
:label="$t('auth_gh_client_id_label')"
:hint="$t('auth_gh_client_id_hint')"
>
</q-input>
</div>
<div class="col-12 col-md-6">
<q-input
filled
v-model="formData.github_client_secret"
type="password"
:label="$t('auth_gh_client_secret_label')"
>
</q-input>
</div>
</div>
</q-card-section>
<q-card-section
v-if="formData.auth_allowed_methods?.includes('keycloak-auth')"
class="q-pl-xl"
>
<strong class="q-my-none q-mb-sm">Keycloak Auth</strong>
<div class="row q-col-gutter-sm q-col-gutter-y-md">
<div class="col-12 col-md-4">
<q-input
filled
v-model="formData.keycloak_discovery_url"
:label="$t('auth_keycloak_label')"
>
</q-input>
</div>
<div class="col-12 col-md-4">
<q-input
filled
v-model="formData.keycloak_client_id"
:label="$t('auth_keycloak_ci_label')"
:hint="$t('auth_keycloak_ci_hint')"
>
</q-input>
</div>
<div class="col-12 col-md-4">
<q-input
filled
v-model="formData.keycloak_client_secret"
type="password"
:label="$t('auth_keycloak_cs_label')"
>
</q-input>
</div>
<div class="col-12 col-md-4">
<q-input
filled
v-model="formData.keycloak_client_custom_org"
:label="$t('auth_keycloak_custom_org_label')"
>
</q-input>
</div>
<div class="col-12 col-md-8">
<q-input
filled
v-model="formData.keycloak_client_custom_icon"
:label="$t('auth_keycloak_custom_icon_label')"
>
</q-input>
</div>
</div>
</q-card-section>
<q-separator></q-separator>
<q-card-section class="q-pa-none">
<br />
<h6 class="q-my-none" v-text="$t('security_tools')"></h6>
<div>
<div class="row">
<div v-if="serverlogEnabled" class="column" style="width: 100%">
<div
class="col bg-primary"
style="padding-left: 5px; max-height: 20px; color: #fafafa"
v-text="$t('server_logs')"
></div>
<div class="col" style="background-color: #292929">
<q-scroll-area
ref="logScroll"
style="padding: 10px; color: #fafafa; height: 320px"
>
<small v-for="log in logs"
><span v-text="log"></span><br
/></small>
</q-scroll-area>
</div>
</div>
<q-btn
@click="toggleServerLog"
dense
flat
color="primary"
:label="
serverlogEnabled
? $t('disable_server_log')
: $t('enable_server_log')
"
></q-btn>
</div>
<br />
<div class="row q-col-gutter-md">
<div class="col-12 col-md-12">
<p v-text="$t('ip_blocker')"></p>
<div class="row q-col-gutter-md">
<div class="col-12 col-md-6">
<q-input
filled
v-model="formBlockedIPs"
@keydown.enter="addBlockedIPs"
type="text"
:label="$t('enter_ip')"
:hint="$t('block_access_hint')"
>
<q-btn
@click="addExtensionsManifest"
dense
flat
icon="add"
></q-btn>
</q-input>
<div>
<q-chip
v-for="blocked_ip in formData.lnbits_blocked_ips"
:key="blocked_ip"
removable
@remove="removeBlockedIPs(blocked_ip)"
color="primary"
text-color="white"
:label="blocked_ip"
class="ellipsis"
></q-chip>
</div>
<br />
</div>
<div class="col-12 col-md-6">
<q-input
filled
v-model="formAllowedIPs"
@keydown.enter="addAllowedIPs"
type="text"
:label="$t('enter_ip')"
:hint="$t('allow_access_hint')"
>
<q-btn
@click="addExtensionsManifest"
dense
flat
icon="add"
></q-btn>
</q-input>
<div>
<q-chip
v-for="allowed_ip in formData.lnbits_allowed_ips"
:key="allowed_ip"
removable
@remove="removeAllowedIPs(allowed_ip)"
color="primary"
text-color="white"
:label="allowed_ip"
class="ellipsis"
></q-chip>
</div>
<br />
</div>
</div>
</div>
<div class="col-12 col-md-12">
<p v-text="$t('rate_limiter')"></p>
<div class="row q-col-gutter-md">
<div class="col-12 col-md-6">
<q-input
filled
type="number"
v-model.number="formData.lnbits_rate_limit_no"
:label="$t('number_of_requests')"
></q-input>
</div>
<div class="col-12 col-md-6">
<q-select
filled
:options="[$t('second'), $t('minute'), $t('hour')]"
v-model="formData.lnbits_rate_limit_unit"
:label="$t('time_unit')"
></q-select>
</div>
</div>
</div>
<div class="col-12 col-md-12">
<p v-text="$t('callback_url_rules')"></p>
<div class="row q-col-gutter-md">
<div class="col-12">
<q-input
filled
v-model="formCallbackUrlRule"
@keydown.enter="addCallbackUrlRule"
type="text"
:label="$t('enter_callback_url_rule')"
:hint="$t('callback_url_rule_hint')"
>
<q-btn
@click="addCallbackUrlRule"
dense
flat
icon="add"
></q-btn>
</q-input>
<div>
<q-chip
v-for="rule in formData.lnbits_callback_url_rules"
:key="rule"
removable
@remove="removeCallbackUrlRule(rule)"
color="primary"
text-color="white"
:label="rule"
class="ellipsis"
></q-chip>
</div>
<br />
</div>
</div>
</div>
</div>
</div>
</q-card-section>
</template>
@@ -0,0 +1,180 @@
<template id="lnbits-admin-server">
<q-card-section class="q-pa-none">
<div>
<h6 class="q-my-none">
<span v-text="$t('currency_settings')"></span>
</h6>
<div class="row q-col-gutter-md">
<div class="col-12 col-md-6">
<p>
<span v-text="$t('allowed_currencies')"></span>
</p>
<q-select
filled
v-model="formData.lnbits_allowed_currencies"
multiple
:hint="$t('allowed_currencies_hint')"
:label="$t('allowed_currencies')"
:options="currencies"
></q-select>
</div>
<div class="col-12 col-md-6">
<p>
<span v-text="$t('default_account_currency')"></span>
</p>
<q-select
filled
v-model="formData.lnbits_default_accounting_currency"
clearable
:hint="$t('default_account_currency_hint')"
:label="$t('currency')"
:options="
formData.lnbits_allowed_currencies?.length
? formData.lnbits_allowed_currencies
: currencies
"
></q-select>
</div>
</div>
<q-separator class="q-mb-lg q-mt-sm"></q-separator>
<h6 class="q-my-none">
<span v-text="$t('payments')"></span>
</h6>
<div class="row q-col-gutter-md">
<div class="col-12 col-md-3">
<p>
<span v-text="$t('max_outgoing_payment_amount')"></span>
</p>
<q-input
filled
type="number"
v-model.number="formData.lnbits_max_outgoing_payment_amount_sats"
:label="$t('max_outgoing_payment_amount')"
step="1"
min="0"
:hint="$t('max_outgoing_payment_amount_desc')"
></q-input>
</div>
<div class="col-12 col-md-3">
<p>
<span v-text="$t('max_incoming_payment_amount')"></span>
</p>
<q-input
filled
type="number"
v-model.number="formData.lnbits_max_incoming_payment_amount_sats"
:label="$t('max_incoming_payment_amount')"
step="1"
min="0"
:hint="$t('max_incoming_payment_amount_desc')"
></q-input>
</div>
<div class="col-12 col-md-6"></div>
</div>
<q-separator class="q-mb-lg q-mt-sm"></q-separator>
<h6 class="q-my-none">
<span v-text="$t('wallet_limiter')"></span>
</h6>
<div class="row q-col-gutter-md">
<div class="col-12 col-md-3">
<q-input
filled
type="number"
v-model.number="formData.lnbits_wallet_limit_max_balance"
:label="$t('wallet_max_ballance')"
></q-input>
</div>
<div class="col-12 col-md-3">
<q-input
filled
type="number"
v-model.number="formData.lnbits_wallet_limit_daily_max_withdraw"
:label="$t('wallet_limit_max_withdraw_per_day')"
></q-input>
</div>
<div class="col-12 col-md-3">
<q-input
filled
type="number"
v-model.number="formData.lnbits_wallet_limit_secs_between_trans"
:label="$t('wallet_limit_secs_between_trans')"
></q-input>
</div>
<div class="col-12 col-md-3">
<q-toggle
v-model="formData.lnbits_only_allow_incoming_payments"
:label="$t('only_incoming_payments_allowed')"
><q-tooltip v-text="$t('disable_outgoing_payments')"></q-tooltip
></q-toggle>
</div>
</div>
<q-separator class="q-mb-lg q-mt-sm"></q-separator>
<h6 class="q-my-none">
<span v-text="$t('service_fee')"></span>
</h6>
<div class="row q-col-gutter-md">
<div class="col-12 col-md-6">
<p><span v-text="$t('service_fee')"></span></p>
<q-input
filled
type="number"
v-model.number="formData.lnbits_service_fee"
:label="$t('service_fee_label')"
step="0.1"
:hint="$t('service_fee_hint')"
></q-input>
<br />
</div>
<div class="col-12 col-md-6">
<p><span v-text="$t('service_fee_max')"></span></p>
<q-input
filled
type="number"
v-model.number="formData.lnbits_service_fee_max"
:label="$t('service_fee_max_label')"
:hint="$t('service_fee_max_hint')"
></q-input>
<br />
</div>
<div class="col-12 col-md-6">
<p><span v-text="$t('fee_wallet')"></span></p>
<q-input
filled
v-model="formData.lnbits_service_fee_wallet"
:label="$t('fee_wallet_label')"
:hint="$t('fee_wallet_hint')"
></q-input>
<br />
</div>
<div class="col-12 col-md-6">
<p>
<span v-text="$t('disable_fee_internal')"></span>
</p>
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label v-text="$t('disable_fee')"></q-item-label>
<q-item-label
caption
v-text="$t('disable_fee_internal_desc')"
></q-item-label>
</q-item-section>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_service_fee_ignore_internal"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
</q-item>
<br />
</div>
</div>
</div>
</q-card-section>
</template>
@@ -0,0 +1,226 @@
<template id="lnbits-admin-site-customisation">
<q-card-section class="q-pa-none">
<h6 class="q-my-none">
<span v-text="$t('ui_management')"></span>
</h6>
<br />
<div>
<div class="row q-col-gutter-md">
<div class="col-12 col-md-5">
<p><span v-text="$t('ui_site_title')"></span></p>
<q-input
filled
type="text"
v-model="formData.lnbits_site_title"
:label="
$t('ui_site_title') + $t('ui_changing_remove_lnbits_elements')
"
></q-input>
<br />
</div>
<div class="col-12 col-md-5">
<p><span v-text="$t('ui_site_tagline')"></span></p>
<q-input
filled
type="text"
v-model="formData.lnbits_site_tagline"
:label="$t('ui_site_tagline')"
></q-input>
<br />
</div>
<div class="col-12 col-md-2 q-mt-xl">
<q-toggle
:tip="$t('ui_toggle_elements_tip')"
v-model="formData.lnbits_show_home_page_elements"
:label="
formData.lnbits_show_home_page_elements
? $t('ui_elements_enable')
: $t('ui_elements_disable')
"
></q-toggle>
</div>
</div>
<div>
<p>
<span v-text="$t('ui_site_description')"></span>
</p>
<q-input
v-model="formData.lnbits_site_description"
filled
type="textarea"
:hint="$t('ui_site_description_hint')"
/>
</div>
<br />
<div class="row q-col-gutter-md">
<div class="col-12 col-md-4">
<p>
<span v-text="$t('ui_default_wallet_name')"></span>
</p>
<q-input
filled
type="text"
v-model="formData.lnbits_default_wallet_name"
:label="$t('lnbits_wallet')"
></q-input>
</div>
<div class="col-12 col-md-4">
<p><span v-text="$t('ui_qr_code_logo')"></span></p>
<q-input
filled
type="text"
v-model="formData.lnbits_qr_logo"
label="https://example.com/image.svg"
:hint="$t('ui_qr_code_logo_hint')"
></q-input>
</div>
</div>
<div class="row q-col-gutter-md q-mt-md">
<div class="col-12 col-md-6">
<p><span v-text="$t('ui_custom_badge')"></span></p>
<div class="row q-col-gutter-md">
<div class="col-12 col-md-8">
<q-input
filled
type="text"
tip="Custom Badge"
v-model.trim="formData.lnbits_custom_badge"
:label="$t('ui_custom_badge_label')"
></q-input>
</div>
<div class="col-12 col-md-4">
<q-select
filled
v-model="formData.lnbits_custom_badge_color"
:options="colors"
:label="$t('ui_custom_badge_color_label')"
></q-select>
</div>
</div>
</div>
<div class="col-12 col-md-6">
<p><span v-text="$t('ui_custom_image')"></span></p>
<q-input
filled
type="text"
tip="Custom Image"
v-model.trim="formData.lnbits_custom_image"
:label="$t('ui_custom_image_label')"
:hint="$t('ui_custom_image_hint')"
></q-input>
</div>
</div>
<br />
<div class="row q-col-gutter-md">
<div class="col-12 col-md-6">
<p><span v-text="$t('themes')"></span></p>
<q-select
filled
v-model="formData.lnbits_theme_options"
multiple
:hint="$t('themes_hint')"
:options="lnbits_theme_options"
:label="$t('themes')"
></q-select>
<br />
</div>
<div class="col-12 col-md-6">
<p><span v-text="$t('custom_logo')"></span></p>
<q-input
filled
type="text"
v-model="formData.lnbits_custom_logo"
label="https://example.com/image.png"
:hint="$t('custom_logo_hint')"
></q-input>
<br />
</div>
</div>
<div class="row q-col-gutter-md">
<div class="col-12 col-md-6">
<p><span v-text="$t('ad_space_title')"></span></p>
<q-input
filled
type="text"
v-model="formData.lnbits_ad_space_title"
:label="$t('ad_space_title_label')"
></q-input>
<br />
</div>
<div class="col-12 col-md-6">
<p><span v-text="$t('ad_slots')"></span></p>
<q-input
class="q-mb-md"
filled
v-model="formData.lnbits_ad_space"
type="text"
:label="$t('ad_slots_label')"
:hint="$t('ad_slots_hint')"
><q-tooltip>
format {url};{img-light};{img-dark},{url};{img-light};{img-dark}"
</q-tooltip>
</q-input>
<q-toggle
v-model="formData.lnbits_ad_space_enabled"
:label="
formData.lnbits_ad_space_enabled
? $t('ads_enabled')
: $t('ads_disabled')
"
/>
<br />
</div>
</div>
<div class="row q-col-gutter-md q-my-md">
<div class="col-12" v-text="$t('ui_default_theme')"></div>
<div class="col-12 col-sm-6 col-lg-3">
<q-select
v-model="formData.lnbits_default_border"
:options="globalBorderOptions"
label="Border"
@update:model-value="applyGlobalBorder"
>
</q-select>
</div>
<div class="col-12 col-sm-6 col-lg-3">
<q-select
v-model="formData.lnbits_default_theme"
:options="lnbits_theme_options"
label="Theme"
@update:model-value="applyGlobalTheme"
>
</q-select>
</div>
<div class="col-12 col-sm-6 col-lg-3">
<q-select
v-model="formData.lnbits_default_reaction"
:options="reactionOptions"
label="Payment reaction"
@update:model-value="applyGlobalReaction"
>
</q-select>
</div>
<div class="col-12 col-sm-6 col-lg-3">
<q-input
type="text"
v-model="formData.lnbits_default_bgimage"
label="Background Image"
@update:model-value="applyGlobalBgimage"
hint="This must be a trusted source. It can change the content and it can log your IP address."
>
</q-input>
</div>
<div class="col-12 col-sm-6 col-lg-3">
<q-toggle
type="bool"
v-model="formData.lnbits_default_gradient"
color="primary"
label="Gradient Background"
>
</q-toggle>
</div>
</div>
</div>
</q-card-section>
</template>
@@ -0,0 +1,83 @@
<template id="lnbits-admin-users">
<q-card-section class="q-pa-none">
<h6 class="q-my-none q-mb-sm">
<span v-text="$t('user_management')"></span>
</h6>
<div class="row">
<div class="col-12 col-md-6 q-pr-sm">
<p><span v-text="$t('admin_users')"></span></p>
<q-input
filled
v-model="formAddAdmin"
@keydown.enter="addAdminUser"
type="text"
:label="$t('admin_users_label')"
:hint="$t('admin_users_hint')"
>
<q-btn @click="addAdminUser" dense flat icon="add"></q-btn>
</q-input>
<div>
<q-chip
v-for="user in formData.lnbits_admin_users"
:key="user"
removable
@remove="removeAdminUser(user)"
color="primary"
text-color="white"
:label="user"
class="ellipsis"
>
</q-chip>
</div>
<br />
</div>
<div class="col-12 col-md-6">
<p><span v-text="$t('allowed_users')"></span></p>
<q-input
filled
v-model="formAddUser"
@keydown.enter="addAllowedUser"
type="text"
:label="$t('allowed_users_label')"
:hint="$t('allowed_users_hint')"
>
<q-btn @click="addAllowedUser" dense flat icon="add"></q-btn>
</q-input>
<div>
<q-chip
v-for="user in formData.lnbits_allowed_users"
:key="user"
removable
@remove="removeAllowedUser(user)"
color="primary"
text-color="white"
:label="user"
class="ellipsis"
>
</q-chip>
</div>
<br />
<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label v-text="$t('allow_creation_user')"></q-item-label>
<q-item-label
caption
v-text="$t('allow_creation_user_desc')"
></q-item-label>
</q-item-section>
<q-item-section avatar>
<q-toggle
size="md"
v-model="formData.lnbits_allow_new_accounts"
checked-icon="check"
color="green"
unchecked-icon="clear"
/>
</q-item-section>
</q-item>
<br />
</div>
</div>
</q-card-section>
</template>