feat: move extension/builder into vue component (#3479)
This commit is contained in:
parent
6bac34fc6b
commit
c2a3fbc6c0
9 changed files with 896 additions and 865 deletions
|
|
@ -1,830 +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">
|
||||
<div class="col-12">
|
||||
<q-stepper
|
||||
v-model="step"
|
||||
ref="stepper"
|
||||
color="primary"
|
||||
animated
|
||||
header-nav
|
||||
class="q-pt-sm"
|
||||
@update:model-value="onStepChange"
|
||||
>
|
||||
<q-step
|
||||
:name="1"
|
||||
title="Describe"
|
||||
icon="info"
|
||||
:done="step > 1"
|
||||
style="min-height: 100px"
|
||||
>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12">
|
||||
<span class="text-h6">
|
||||
Tell us something about your extension:
|
||||
</span>
|
||||
<ul>
|
||||
<li>This is the first step, you can return and change it.</li>
|
||||
<li>
|
||||
The <code>`name`</code> and
|
||||
<code>`sort description`</code> fields are what the users will
|
||||
see when browsing the list of extensions.
|
||||
</li>
|
||||
<li>
|
||||
The <code>`id`</code> field is used internally and in the URL of
|
||||
your extension.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- todo: add icon -->
|
||||
|
||||
<div class="col-12">
|
||||
<div>
|
||||
<q-btn
|
||||
color="primary"
|
||||
label="Upload Existing config"
|
||||
@click="$refs.extensionDataInput.click()"
|
||||
class="q-mb-md"
|
||||
/>
|
||||
<input
|
||||
type="file"
|
||||
ref="extensionDataInput"
|
||||
accept="application/json"
|
||||
style="display: none"
|
||||
@change="onJsonDataInput"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<q-separator class="q-mt-sm"></q-separator>
|
||||
<div class="row q-col-gutter-md q-mt-md">
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<q-input
|
||||
filled
|
||||
v-model="extensionData.name"
|
||||
label="Extension Name"
|
||||
hint="The name of your extension"
|
||||
>
|
||||
</q-input>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<q-input
|
||||
filled
|
||||
v-model="extensionData.id"
|
||||
label="Extension Id"
|
||||
hint="Lowercase letters, numbers, and underscores only (snake_case). This will be used in the URL."
|
||||
>
|
||||
</q-input>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<q-input
|
||||
filled
|
||||
v-model="extensionData.short_description"
|
||||
label="Short Description"
|
||||
hint="A short description that is shown in the extension list."
|
||||
>
|
||||
</q-input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-mt-lg">
|
||||
<div class="col-12">
|
||||
<q-input
|
||||
filled
|
||||
v-model="extensionData.description"
|
||||
label="Description"
|
||||
hint="A detailed description of your extension."
|
||||
type="textarea"
|
||||
rows="3"
|
||||
maxlength="1000"
|
||||
>
|
||||
</q-input>
|
||||
</div>
|
||||
</div>
|
||||
</q-step>
|
||||
|
||||
<q-step
|
||||
:name="2"
|
||||
title="Settings"
|
||||
icon="settings"
|
||||
:done="step > 2"
|
||||
style="min-height: 100px"
|
||||
>
|
||||
<div class="row q-col-gutter-md q-mt-md">
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<iframe
|
||||
ref="iframeStep2"
|
||||
class="full-width"
|
||||
height="400px"
|
||||
sandbox="allow-scripts allow-same-origin"
|
||||
></iframe>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<q-btn
|
||||
@click="previewExtension('settings')"
|
||||
color="primary"
|
||||
outline
|
||||
label="Refresh Preview"
|
||||
class="full-width q-mb-md"
|
||||
></q-btn>
|
||||
<q-toggle
|
||||
v-model="extensionData.settings_data.enabled"
|
||||
label="Generate Settings Fields"
|
||||
size="md"
|
||||
color="green"
|
||||
/>
|
||||
<br />
|
||||
|
||||
<ul>
|
||||
<li>Define what settings your extension will have.</li>
|
||||
<li>
|
||||
You can choose if each user has its own settings or if the
|
||||
settings are global (set by the admin).
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<q-separator
|
||||
v-if="extensionData.settings_data.enabled"
|
||||
class="q-mt-sm"
|
||||
></q-separator>
|
||||
<div v-if="extensionData.settings_data.enabled" class="row q-mt-lg">
|
||||
<div class="col-md-2 col-sm-12">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="extensionData.settings_data.type"
|
||||
:options="settingsTypes"
|
||||
></q-select>
|
||||
</div>
|
||||
<div class="col-md-10 col-sm-12 q-pt-sm">
|
||||
<q-badge
|
||||
v-if="extensionData.settings_data.type === 'user'"
|
||||
outline
|
||||
class="text-caption q-ml-md"
|
||||
>Each user can set its own settings for this extension.</q-badge
|
||||
>
|
||||
<q-badge v-else outline class="text-caption q-ml-md"
|
||||
>Settings are set by the admin and apply to all users of the
|
||||
extension</q-badge
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="extensionData.settings_data.enabled" class="row q-mt-lg">
|
||||
<div class="col-12">
|
||||
<lnbits-data-fields
|
||||
:fields="extensionData.settings_data.fields"
|
||||
:hide-advanced="true"
|
||||
></lnbits-data-fields>
|
||||
</div>
|
||||
</div>
|
||||
</q-step>
|
||||
|
||||
<q-step
|
||||
:name="3"
|
||||
:done="step > 3"
|
||||
title="Owner Data"
|
||||
icon="list"
|
||||
style="min-height: 100px"
|
||||
>
|
||||
<div class="row q-col-gutter-md q-mt-md">
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<iframe
|
||||
ref="iframeStep3"
|
||||
class="full-width"
|
||||
height="400px"
|
||||
sandbox="allow-scripts allow-same-origin"
|
||||
></iframe>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<q-btn
|
||||
@click="previewExtension('owner_data')"
|
||||
color="primary"
|
||||
outline
|
||||
label="Refresh Preview"
|
||||
class="full-width q-mb-md"
|
||||
></q-btn>
|
||||
<q-input
|
||||
v-model="extensionData.owner_data.name"
|
||||
filled
|
||||
label="Owner Table Name"
|
||||
hint="CamelCase name for the owner data table (e.g. Campaign, PoS, etc.)"
|
||||
class="q-mb-xl"
|
||||
>
|
||||
</q-input>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
The owner of the extension manages this data. It can add, remove
|
||||
and update instances of it.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Some fileds are present by default, like
|
||||
<code>created_at</code>, <code>updated_at</code> and
|
||||
<code>extra</code>.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row q-mt-lg">
|
||||
<div class="col-12">
|
||||
<lnbits-data-fields
|
||||
:fields="extensionData.owner_data.fields"
|
||||
></lnbits-data-fields>
|
||||
</div>
|
||||
</div>
|
||||
</q-step>
|
||||
|
||||
<q-step
|
||||
:name="4"
|
||||
:done="step > 4"
|
||||
title="Client Data"
|
||||
icon="blur_linear"
|
||||
style="min-height: 100px"
|
||||
>
|
||||
<div class="row q-col-gutter-md q-mt-md">
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<iframe
|
||||
ref="iframeStep4"
|
||||
class="full-width"
|
||||
height="400px"
|
||||
sandbox="allow-scripts allow-same-origin"
|
||||
></iframe>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<q-btn
|
||||
@click="previewExtension('client_data')"
|
||||
color="primary"
|
||||
outline
|
||||
label="Refresh Preview"
|
||||
class="full-width q-mb-md"
|
||||
></q-btn>
|
||||
<!-- <q-toggle
|
||||
v-model="extensionData.client_data.enabled"
|
||||
label="Generate Client Table"
|
||||
disable
|
||||
size="md"
|
||||
color="green"
|
||||
/>
|
||||
|
||||
<br /> -->
|
||||
<q-input
|
||||
v-if="extensionData.client_data.enabled"
|
||||
v-model="extensionData.client_data.name"
|
||||
filled
|
||||
label="Client Table Name"
|
||||
hint="CamelCase name for the client data table (e.g. Donation, Payment, etc.)"
|
||||
class="q-mb-xl"
|
||||
>
|
||||
</q-input>
|
||||
<ul>
|
||||
<li>
|
||||
This data is created by users of the extension. Usually when
|
||||
they submit a form or make a payment.
|
||||
</li>
|
||||
<li>
|
||||
The owner of the extension can view this data, but should not
|
||||
modify it.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<q-separator
|
||||
v-if="extensionData.client_data.enabled"
|
||||
class="q-mt-sm"
|
||||
></q-separator>
|
||||
<div v-if="extensionData.client_data.enabled" class="row q-mt-lg">
|
||||
<div class="col-12">
|
||||
<lnbits-data-fields
|
||||
:fields="extensionData.client_data.fields"
|
||||
></lnbits-data-fields>
|
||||
</div>
|
||||
</div>
|
||||
</q-step>
|
||||
|
||||
<q-step
|
||||
:name="5"
|
||||
:done="step > 5"
|
||||
title="Public Pages"
|
||||
icon="link"
|
||||
style="min-height: 100px"
|
||||
>
|
||||
<div class="row q-col-gutter-md q-mt-md">
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<iframe
|
||||
ref="iframeStep5"
|
||||
class="full-width"
|
||||
height="400px"
|
||||
sandbox="allow-scripts allow-same-origin"
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<q-btn
|
||||
@click="previewExtension('public_page')"
|
||||
color="primary"
|
||||
outline
|
||||
label="Refresh Preview"
|
||||
class="full-width q-mb-md"
|
||||
></q-btn>
|
||||
<q-toggle
|
||||
v-model="extensionData.public_page.has_public_page"
|
||||
label="Generate Public Page"
|
||||
size="md"
|
||||
color="green"
|
||||
/>
|
||||
<br />
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Most extensions have a public page that can be shared (this page
|
||||
will still be accessible even if you have restricted access to
|
||||
your LNbits install).
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="extensionData.public_page.has_public_page">
|
||||
<div class="row q-col-gutter-md q-mt-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<q-item tag="label" v-ripple>
|
||||
<q-item-section>
|
||||
<q-item-label>Public page title</q-item-label>
|
||||
<q-item-label caption
|
||||
>Select the field from the
|
||||
<code v-text="extensionData.owner_data.name"></code>
|
||||
(Owner Data) that will be used as a title for the public
|
||||
page.</q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="extensionData.public_page.owner_data_fields.name"
|
||||
:options="[''].concat(extensionData.owner_data.fields.map(f => f.name))"
|
||||
></q-select>
|
||||
</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>Public page description</q-item-label>
|
||||
<q-item-label caption
|
||||
>Select the field from the
|
||||
<code v-text="extensionData.owner_data.name"></code>
|
||||
(Owner Data) that will be used as a description for the
|
||||
public page.</q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="extensionData.public_page.owner_data_fields.description"
|
||||
:options="[''].concat(extensionData.owner_data.fields.map(f => f.name))"
|
||||
></q-select>
|
||||
</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>Public page inputs</q-item-label>
|
||||
<q-item-label caption>
|
||||
<ul class="q-pa-none q-ma-none">
|
||||
<li>
|
||||
Select the fields from the
|
||||
<code v-text="extensionData.client_data.name"></code
|
||||
> (Client Data) that will be shown as inputs in
|
||||
the public page form.
|
||||
</li>
|
||||
<li>You can select multiple fields.</li>
|
||||
<li>
|
||||
A corresponding input field will be created for each
|
||||
selected field.
|
||||
</li>
|
||||
</ul>
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
multiple
|
||||
use-chips
|
||||
v-model="extensionData.public_page.client_data_fields.public_inputs"
|
||||
:options="extensionData.client_data.fields.map(f => f.name)"
|
||||
></q-select>
|
||||
</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>Generate Action Button</q-item-label>
|
||||
<q-item-label caption>
|
||||
<ul class="q-pa-none q-ma-none">
|
||||
<li>
|
||||
If enabled, the public page will have a button to
|
||||
perform an action (e.g. generate a payment request).
|
||||
</li>
|
||||
<li>
|
||||
The action will use the selected input fields from
|
||||
<code v-text="extensionData.client_data.name"></code
|
||||
> (Client Data) as parameters.
|
||||
</li>
|
||||
<li>
|
||||
A corresponding REST API endpoint will be created.
|
||||
</li>
|
||||
</ul></q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-toggle
|
||||
v-model="extensionData.public_page.action_fields.generate_action"
|
||||
size="md"
|
||||
color="green"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
</div>
|
||||
<q-separator
|
||||
v-if="extensionData.public_page.action_fields.generate_action"
|
||||
class="q-mt-sm"
|
||||
></q-separator>
|
||||
|
||||
<div v-if="extensionData.public_page.action_fields.generate_action">
|
||||
<div class="row q-col-gutter-md q-mt-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<q-item tag="label" v-ripple>
|
||||
<q-item-section>
|
||||
<q-item-label>Generate Payment Logic</q-item-label>
|
||||
<q-item-label caption>
|
||||
<ul class="q-pa-none q-ma-none">
|
||||
<li>
|
||||
If enabled, the endpoint will create an invoice from
|
||||
the submitted data and the UI will show the QR code
|
||||
with the invoice.
|
||||
</li>
|
||||
<li>
|
||||
A listener will be created to check for the pay event.
|
||||
</li>
|
||||
<li>You must map the fieds.</li>
|
||||
</ul></q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-toggle
|
||||
v-model="extensionData.public_page.action_fields.generate_payment_logic"
|
||||
size="md"
|
||||
color="green"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-6"></div>
|
||||
</div>
|
||||
<div
|
||||
v-if="extensionData.public_page.action_fields.generate_action && extensionData.public_page.action_fields.generate_payment_logic"
|
||||
class="row q-col-gutter-md q-mt-md"
|
||||
>
|
||||
<div class="col-12 col-md-6">
|
||||
<q-item tag="label" v-ripple>
|
||||
<q-item-section>
|
||||
<q-item-label>Wallet</q-item-label>
|
||||
<q-item-label caption>
|
||||
<ul class="q-pa-none q-ma-none">
|
||||
<li>
|
||||
Select the field from the
|
||||
<code v-text="extensionData.owner_data.name"></code
|
||||
> (Owner Data) that represents the wallet which
|
||||
will generate the invoice and receive the payments.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Only fields with the type <code>Wallet</code> will be
|
||||
shown.
|
||||
</li>
|
||||
</ul>
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="extensionData.public_page.action_fields.wallet_id"
|
||||
:options="[''].concat(extensionData.owner_data.fields.filter(f => f.type === 'wallet').map(f => f.name))"
|
||||
></q-select>
|
||||
</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>Currency</q-item-label>
|
||||
<q-item-label caption>
|
||||
<ul class="q-pa-none q-ma-none">
|
||||
<li>
|
||||
Select the field from the
|
||||
<code v-text="extensionData.owner_data.name"></code
|
||||
> (Owner Data) that represents the currency
|
||||
which will be used to for the amount.
|
||||
</li>
|
||||
<li>
|
||||
Only fields with the type <code>Currency</code> will
|
||||
be shown.
|
||||
</li>
|
||||
<li>Empty if you want to use sats.</li>
|
||||
</ul>
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="extensionData.public_page.action_fields.currency"
|
||||
:options="[''].concat(extensionData.owner_data.fields.filter(f => f.type === 'currency').map(f => f.name))"
|
||||
></q-select>
|
||||
</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>Amount</q-item-label>
|
||||
<q-item-label caption>
|
||||
<ul class="q-pa-none q-ma-none">
|
||||
<li>
|
||||
Select the field from the
|
||||
<code v-text="extensionData.owner_data.name"></code
|
||||
> (Owner Data) or
|
||||
<code v-text="extensionData.client_data.name"></code
|
||||
> (Client Data) that represents the amount (in
|
||||
the selected currency).
|
||||
</li>
|
||||
<li>
|
||||
Only fields with the type <code>Integer</code> and
|
||||
<code>Float</code> will be shown.
|
||||
</li>
|
||||
</ul>
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="extensionData.public_page.action_fields.amount_source"
|
||||
:options="amountSource"
|
||||
class="q-mr-sm"
|
||||
></q-select>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="extensionData.public_page.action_fields.amount"
|
||||
:options="paymentActionAmountFields"
|
||||
></q-select>
|
||||
</div>
|
||||
</div>
|
||||
</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>Paid Flag</q-item-label>
|
||||
<q-item-label caption>
|
||||
<ul class="q-pa-none q-ma-none">
|
||||
<li>
|
||||
Select the field from the
|
||||
<code v-text="extensionData.client_data.name"></code
|
||||
> (Client Data) that will be set to true when
|
||||
the invoice is paid.
|
||||
</li>
|
||||
<li>
|
||||
Only fields with the type <code>Boolean</code> will be
|
||||
shown.
|
||||
</li>
|
||||
</ul>
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="extensionData.public_page.action_fields.paid_flag"
|
||||
:options="[''].concat(extensionData.client_data.fields.filter(f => f.type === 'bool').map(f => f.name))"
|
||||
></q-select>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</q-step>
|
||||
|
||||
<q-step
|
||||
:name="6"
|
||||
:done="step > 6"
|
||||
title="Publish"
|
||||
icon="publish"
|
||||
style="min-height: 100px"
|
||||
>
|
||||
<div v-if="g.user.admin" class="row">
|
||||
<div class="col-md-4 col-sm-12 col-xs-12">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="extensionData.stub_version"
|
||||
hint="The version of the extension stub. Make sure it is compatible with your LNbits install."
|
||||
:options="extensionStubVersions.map(f => f.version)"
|
||||
></q-select>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-12 col-xs-12">
|
||||
<q-btn
|
||||
@click="cleanCacheData()"
|
||||
color="grey"
|
||||
outline
|
||||
label="Clean Cache"
|
||||
class="q-ml-md"
|
||||
/>
|
||||
<q-icon
|
||||
name="info"
|
||||
size="md"
|
||||
color="primary"
|
||||
class="cursor-pointer q-ml-xs q-mb-xs"
|
||||
>
|
||||
<q-tooltip>
|
||||
<ul class="q-pl-sm">
|
||||
<li>
|
||||
The extension builder uses caching to speed up the build
|
||||
process.
|
||||
</li>
|
||||
<li>
|
||||
This action clears old data and redownloads the Extension
|
||||
Builder Stub release.
|
||||
</li>
|
||||
</ul>
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="g.user.admin" class="row q-mt-md">
|
||||
<div class="col-md-4 col-sm-12 col-xs-12">
|
||||
<div class="row">
|
||||
<q-btn
|
||||
@click="buildExtensionAndDeploy()"
|
||||
color="primary"
|
||||
label="Build and Deploy (Admin Only)"
|
||||
class="col"
|
||||
/>
|
||||
<q-icon
|
||||
name="info"
|
||||
size="md"
|
||||
color="primary"
|
||||
class="cursor-pointer q-ml-sm self-center"
|
||||
>
|
||||
<q-tooltip>
|
||||
<ul class="q-pl-sm">
|
||||
<li>
|
||||
Installs the extension directly to this LNbits instance.
|
||||
</li>
|
||||
<li>
|
||||
The extension will be enabled by default, and available to
|
||||
all users.
|
||||
</li>
|
||||
</ul>
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row q-mt-md">
|
||||
<div class="col-md-4 col-sm-12 col-xs-12">
|
||||
<div class="row">
|
||||
<q-btn
|
||||
@click="buildExtension()"
|
||||
outline
|
||||
color="gray"
|
||||
label="Download Extension Zip"
|
||||
icon="download"
|
||||
class="col"
|
||||
/>
|
||||
<q-icon
|
||||
name="info"
|
||||
size="md"
|
||||
color="primary"
|
||||
class="cursor-pointer q-ml-sm self-center"
|
||||
>
|
||||
<q-tooltip>
|
||||
Builds the extension and downloads a zip file with the code.
|
||||
You can then install it manually in your LNbits instance.
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</q-step>
|
||||
|
||||
<template v-slot:navigation>
|
||||
<q-separator></q-separator>
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-sm-12 q-pl-md q-pt-md">
|
||||
<q-btn
|
||||
v-if="step == 1"
|
||||
label="Clear All Data"
|
||||
color="negative"
|
||||
@click="clearAllData"
|
||||
></q-btn>
|
||||
<q-btn
|
||||
v-else
|
||||
flat
|
||||
color="grey-8"
|
||||
class="q-mr-sm"
|
||||
@click="previousStep()"
|
||||
label="Back"
|
||||
icon="chevron_left"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-12 q-pr-md q-pb-md">
|
||||
<q-stepper-navigation class="float-right">
|
||||
<q-btn
|
||||
v-if="step < 6"
|
||||
@click="nextStep()"
|
||||
color="primary"
|
||||
label="Next"
|
||||
></q-btn>
|
||||
<template v-else>
|
||||
<q-btn
|
||||
@click="exportJsonData()"
|
||||
color="primary"
|
||||
label="Export JSON Data"
|
||||
></q-btn>
|
||||
<q-icon
|
||||
name="info"
|
||||
size="md"
|
||||
color="primary"
|
||||
class="cursor-pointer q-ml-sm self-center"
|
||||
>
|
||||
<q-tooltip>
|
||||
<ul class="q-pl-sm">
|
||||
<li>
|
||||
Exports the config JSON so it can be later imported or
|
||||
shared.
|
||||
</li>
|
||||
<li>
|
||||
This JSON is also added to the zip in a file called
|
||||
`builder.json`.
|
||||
</li>
|
||||
</ul>
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</template>
|
||||
</q-stepper-navigation>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</q-stepper>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-col-gutter-md"></div>
|
||||
|
||||
{% endblock %}
|
||||
|
|
@ -213,24 +213,6 @@ async def extensions(request: Request, user: User = Depends(check_user_exists)):
|
|||
)
|
||||
|
||||
|
||||
@generic_router.get(
|
||||
"/extensions/builder",
|
||||
name="extensions builder",
|
||||
dependencies=[Depends(check_extension_builder)],
|
||||
)
|
||||
async def extensions_builder(
|
||||
request: Request, user: User = Depends(check_user_exists)
|
||||
) -> HTMLResponse:
|
||||
return template_renderer().TemplateResponse(
|
||||
request,
|
||||
"core/extensions_builder.html",
|
||||
{
|
||||
"user": user.json(),
|
||||
"ajax": _is_ajax_request(request),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@generic_router.get(
|
||||
"/extensions/builder/preview/{ext_id}",
|
||||
name="extensions builder",
|
||||
|
|
@ -392,6 +374,9 @@ admin_ui_checks = [Depends(check_admin), Depends(check_admin_ui)]
|
|||
@generic_router.get("/audit", dependencies=admin_ui_checks)
|
||||
@generic_router.get("/node", dependencies=admin_ui_checks)
|
||||
@generic_router.get("/admin", dependencies=admin_ui_checks)
|
||||
@generic_router.get(
|
||||
"/extensions/builder", dependencies=[Depends(check_extension_builder)]
|
||||
)
|
||||
async def index(
|
||||
request: Request, user: User = Depends(check_user_exists)
|
||||
) -> HTMLResponse:
|
||||
|
|
|
|||
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
|
|
@ -148,15 +148,6 @@ const routes = [
|
|||
scripts: ['/static/js/extensions.js']
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/extensions/builder',
|
||||
name: 'ExtensionsBuilder',
|
||||
component: DynamicComponent,
|
||||
props: {
|
||||
fetchUrl: '/extensions/builder',
|
||||
scripts: ['/static/js/extensions_builder.js']
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/node',
|
||||
name: 'Node',
|
||||
|
|
@ -196,6 +187,11 @@ const routes = [
|
|||
path: '/account',
|
||||
name: 'Account',
|
||||
component: PageAccount
|
||||
},
|
||||
{
|
||||
path: '/extensions/builder',
|
||||
name: 'ExtensionsBuilder',
|
||||
component: PageExtensionBuilder
|
||||
}
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
window.ExtensionsBuilderPageLogic = {
|
||||
data: function () {
|
||||
window.PageExtensionBuilder = {
|
||||
template: '#page-extension-builder',
|
||||
mixins: [windowMixin],
|
||||
data() {
|
||||
return {
|
||||
step: 1,
|
||||
previewStepNames: {
|
||||
|
|
@ -92,7 +94,6 @@ window.ExtensionsBuilderPageLogic = {
|
|||
paymentActionAmountFields() {
|
||||
const amount_source =
|
||||
this.extensionData.public_page.action_fields.amount_source
|
||||
console.log('### amount_source:', amount_source)
|
||||
if (!amount_source) return ['']
|
||||
|
||||
if (amount_source === 'owner_data') {
|
||||
|
|
@ -325,7 +326,7 @@ window.ExtensionsBuilderPageLogic = {
|
|||
this.extensionDataCleanString = JSON.stringify(this.extensionData)
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
created() {
|
||||
this.initBasicData()
|
||||
|
||||
const extensionData = this.$q.localStorage.getItem(
|
||||
|
|
@ -345,6 +346,5 @@ window.ExtensionsBuilderPageLogic = {
|
|||
setTimeout(() => {
|
||||
this.refreshIframe()
|
||||
}, 1000)
|
||||
},
|
||||
mixins: [windowMixin]
|
||||
}
|
||||
}
|
||||
|
|
@ -43,6 +43,7 @@
|
|||
"js/lnurl.js"
|
||||
],
|
||||
"components": [
|
||||
"js/pages/extensions_builder.js",
|
||||
"js/pages/payments.js",
|
||||
"js/pages/node.js",
|
||||
"js/pages/node-public.js",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{% include('pages/payments.vue') %} {% include('pages/node.vue') %} {%
|
||||
include('pages/audit.vue') %} {% include('pages/wallets.vue') %} {%
|
||||
include('pages/users.vue') %} {% include('pages/admin.vue') %} {%
|
||||
include('pages/account.vue') %}
|
||||
include('pages/account.vue') %} {% include('pages/extensions_builder.vue') %}
|
||||
|
|
|
|||
878
lnbits/templates/pages/extensions_builder.vue
Normal file
878
lnbits/templates/pages/extensions_builder.vue
Normal file
|
|
@ -0,0 +1,878 @@
|
|||
<template id="page-extension-builder">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<q-stepper
|
||||
v-model="step"
|
||||
ref="stepper"
|
||||
color="primary"
|
||||
animated
|
||||
header-nav
|
||||
class="q-pt-sm"
|
||||
@update:model-value="onStepChange"
|
||||
>
|
||||
<q-step
|
||||
:name="1"
|
||||
title="Describe"
|
||||
icon="info"
|
||||
:done="step > 1"
|
||||
style="min-height: 100px"
|
||||
>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12">
|
||||
<span class="text-h6">
|
||||
Tell us something about your extension:
|
||||
</span>
|
||||
<ul>
|
||||
<li>This is the first step, you can return and change it.</li>
|
||||
<li>
|
||||
The <code>`name`</code> and
|
||||
<code>`sort description`</code> fields are what the users will
|
||||
see when browsing the list of extensions.
|
||||
</li>
|
||||
<li>
|
||||
The <code>`id`</code> field is used internally and in the URL
|
||||
of your extension.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- todo: add icon -->
|
||||
|
||||
<div class="col-12">
|
||||
<div>
|
||||
<q-btn
|
||||
color="primary"
|
||||
label="Upload Existing config"
|
||||
@click="$refs.extensionDataInput.click()"
|
||||
class="q-mb-md"
|
||||
/>
|
||||
<input
|
||||
type="file"
|
||||
ref="extensionDataInput"
|
||||
accept="application/json"
|
||||
style="display: none"
|
||||
@change="onJsonDataInput"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<q-separator class="q-mt-sm"></q-separator>
|
||||
<div class="row q-col-gutter-md q-mt-md">
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<q-input
|
||||
filled
|
||||
v-model="extensionData.name"
|
||||
label="Extension Name"
|
||||
hint="The name of your extension"
|
||||
>
|
||||
</q-input>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<q-input
|
||||
filled
|
||||
v-model="extensionData.id"
|
||||
label="Extension Id"
|
||||
hint="Lowercase letters, numbers, and underscores only (snake_case). This will be used in the URL."
|
||||
>
|
||||
</q-input>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<q-input
|
||||
filled
|
||||
v-model="extensionData.short_description"
|
||||
label="Short Description"
|
||||
hint="A short description that is shown in the extension list."
|
||||
>
|
||||
</q-input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-mt-lg">
|
||||
<div class="col-12">
|
||||
<q-input
|
||||
filled
|
||||
v-model="extensionData.description"
|
||||
label="Description"
|
||||
hint="A detailed description of your extension."
|
||||
type="textarea"
|
||||
rows="3"
|
||||
maxlength="1000"
|
||||
>
|
||||
</q-input>
|
||||
</div>
|
||||
</div>
|
||||
</q-step>
|
||||
|
||||
<q-step
|
||||
:name="2"
|
||||
title="Settings"
|
||||
icon="settings"
|
||||
:done="step > 2"
|
||||
style="min-height: 100px"
|
||||
>
|
||||
<div class="row q-col-gutter-md q-mt-md">
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<iframe
|
||||
ref="iframeStep2"
|
||||
class="full-width"
|
||||
height="400px"
|
||||
sandbox="allow-scripts allow-same-origin"
|
||||
></iframe>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<q-btn
|
||||
@click="previewExtension('settings')"
|
||||
color="primary"
|
||||
outline
|
||||
label="Refresh Preview"
|
||||
class="full-width q-mb-md"
|
||||
></q-btn>
|
||||
<q-toggle
|
||||
v-model="extensionData.settings_data.enabled"
|
||||
label="Generate Settings Fields"
|
||||
size="md"
|
||||
color="green"
|
||||
/>
|
||||
<br />
|
||||
|
||||
<ul>
|
||||
<li>Define what settings your extension will have.</li>
|
||||
<li>
|
||||
You can choose if each user has its own settings or if the
|
||||
settings are global (set by the admin).
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<q-separator
|
||||
v-if="extensionData.settings_data.enabled"
|
||||
class="q-mt-sm"
|
||||
></q-separator>
|
||||
<div v-if="extensionData.settings_data.enabled" class="row q-mt-lg">
|
||||
<div class="col-md-2 col-sm-12">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="extensionData.settings_data.type"
|
||||
:options="settingsTypes"
|
||||
></q-select>
|
||||
</div>
|
||||
<div class="col-md-10 col-sm-12 q-pt-sm">
|
||||
<q-badge
|
||||
v-if="extensionData.settings_data.type === 'user'"
|
||||
outline
|
||||
class="text-caption q-ml-md"
|
||||
>Each user can set its own settings for this extension.</q-badge
|
||||
>
|
||||
<q-badge v-else outline class="text-caption q-ml-md"
|
||||
>Settings are set by the admin and apply to all users of the
|
||||
extension</q-badge
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="extensionData.settings_data.enabled" class="row q-mt-lg">
|
||||
<div class="col-12">
|
||||
<lnbits-data-fields
|
||||
:fields="extensionData.settings_data.fields"
|
||||
:hide-advanced="true"
|
||||
></lnbits-data-fields>
|
||||
</div>
|
||||
</div>
|
||||
</q-step>
|
||||
|
||||
<q-step
|
||||
:name="3"
|
||||
:done="step > 3"
|
||||
title="Owner Data"
|
||||
icon="list"
|
||||
style="min-height: 100px"
|
||||
>
|
||||
<div class="row q-col-gutter-md q-mt-md">
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<iframe
|
||||
ref="iframeStep3"
|
||||
class="full-width"
|
||||
height="400px"
|
||||
sandbox="allow-scripts allow-same-origin"
|
||||
></iframe>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<q-btn
|
||||
@click="previewExtension('owner_data')"
|
||||
color="primary"
|
||||
outline
|
||||
label="Refresh Preview"
|
||||
class="full-width q-mb-md"
|
||||
></q-btn>
|
||||
<q-input
|
||||
v-model="extensionData.owner_data.name"
|
||||
filled
|
||||
label="Owner Table Name"
|
||||
hint="CamelCase name for the owner data table (e.g. Campaign, PoS, etc.)"
|
||||
class="q-mb-xl"
|
||||
>
|
||||
</q-input>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
The owner of the extension manages this data. It can add,
|
||||
remove and update instances of it.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Some fileds are present by default, like
|
||||
<code>created_at</code>, <code>updated_at</code> and
|
||||
<code>extra</code>.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row q-mt-lg">
|
||||
<div class="col-12">
|
||||
<lnbits-data-fields
|
||||
:fields="extensionData.owner_data.fields"
|
||||
></lnbits-data-fields>
|
||||
</div>
|
||||
</div>
|
||||
</q-step>
|
||||
|
||||
<q-step
|
||||
:name="4"
|
||||
:done="step > 4"
|
||||
title="Client Data"
|
||||
icon="blur_linear"
|
||||
style="min-height: 100px"
|
||||
>
|
||||
<div class="row q-col-gutter-md q-mt-md">
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<iframe
|
||||
ref="iframeStep4"
|
||||
class="full-width"
|
||||
height="400px"
|
||||
sandbox="allow-scripts allow-same-origin"
|
||||
></iframe>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<q-btn
|
||||
@click="previewExtension('client_data')"
|
||||
color="primary"
|
||||
outline
|
||||
label="Refresh Preview"
|
||||
class="full-width q-mb-md"
|
||||
></q-btn>
|
||||
<!-- <q-toggle
|
||||
v-model="extensionData.client_data.enabled"
|
||||
label="Generate Client Table"
|
||||
disable
|
||||
size="md"
|
||||
color="green"
|
||||
/>
|
||||
|
||||
<br /> -->
|
||||
<q-input
|
||||
v-if="extensionData.client_data.enabled"
|
||||
v-model="extensionData.client_data.name"
|
||||
filled
|
||||
label="Client Table Name"
|
||||
hint="CamelCase name for the client data table (e.g. Donation, Payment, etc.)"
|
||||
class="q-mb-xl"
|
||||
>
|
||||
</q-input>
|
||||
<ul>
|
||||
<li>
|
||||
This data is created by users of the extension. Usually when
|
||||
they submit a form or make a payment.
|
||||
</li>
|
||||
<li>
|
||||
The owner of the extension can view this data, but should not
|
||||
modify it.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<q-separator
|
||||
v-if="extensionData.client_data.enabled"
|
||||
class="q-mt-sm"
|
||||
></q-separator>
|
||||
<div v-if="extensionData.client_data.enabled" class="row q-mt-lg">
|
||||
<div class="col-12">
|
||||
<lnbits-data-fields
|
||||
:fields="extensionData.client_data.fields"
|
||||
></lnbits-data-fields>
|
||||
</div>
|
||||
</div>
|
||||
</q-step>
|
||||
|
||||
<q-step
|
||||
:name="5"
|
||||
:done="step > 5"
|
||||
title="Public Pages"
|
||||
icon="link"
|
||||
style="min-height: 100px"
|
||||
>
|
||||
<div class="row q-col-gutter-md q-mt-md">
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<iframe
|
||||
ref="iframeStep5"
|
||||
class="full-width"
|
||||
height="400px"
|
||||
sandbox="allow-scripts allow-same-origin"
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<q-btn
|
||||
@click="previewExtension('public_page')"
|
||||
color="primary"
|
||||
outline
|
||||
label="Refresh Preview"
|
||||
class="full-width q-mb-md"
|
||||
></q-btn>
|
||||
<q-toggle
|
||||
v-model="extensionData.public_page.has_public_page"
|
||||
label="Generate Public Page"
|
||||
size="md"
|
||||
color="green"
|
||||
/>
|
||||
<br />
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Most extensions have a public page that can be shared (this
|
||||
page will still be accessible even if you have restricted
|
||||
access to your LNbits install).
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="extensionData.public_page.has_public_page">
|
||||
<div class="row q-col-gutter-md q-mt-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<q-item tag="label" v-ripple>
|
||||
<q-item-section>
|
||||
<q-item-label>Public page title</q-item-label>
|
||||
<q-item-label caption
|
||||
>Select the field from the
|
||||
<code v-text="extensionData.owner_data.name"></code>
|
||||
(Owner Data) that will be used as a title for the public
|
||||
page.</q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="extensionData.public_page.owner_data_fields.name"
|
||||
:options="
|
||||
[''].concat(
|
||||
extensionData.owner_data.fields.map(f => f.name)
|
||||
)
|
||||
"
|
||||
></q-select>
|
||||
</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>Public page description</q-item-label>
|
||||
<q-item-label caption
|
||||
>Select the field from the
|
||||
<code v-text="extensionData.owner_data.name"></code>
|
||||
(Owner Data) that will be used as a description for the
|
||||
public page.</q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="
|
||||
extensionData.public_page.owner_data_fields.description
|
||||
"
|
||||
:options="
|
||||
[''].concat(
|
||||
extensionData.owner_data.fields.map(f => f.name)
|
||||
)
|
||||
"
|
||||
></q-select>
|
||||
</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>Public page inputs</q-item-label>
|
||||
<q-item-label caption>
|
||||
<ul class="q-pa-none q-ma-none">
|
||||
<li>
|
||||
Select the fields from the
|
||||
<code v-text="extensionData.client_data.name"></code
|
||||
> (Client Data) that will be shown as inputs in
|
||||
the public page form.
|
||||
</li>
|
||||
<li>You can select multiple fields.</li>
|
||||
<li>
|
||||
A corresponding input field will be created for each
|
||||
selected field.
|
||||
</li>
|
||||
</ul>
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
multiple
|
||||
use-chips
|
||||
v-model="
|
||||
extensionData.public_page.client_data_fields
|
||||
.public_inputs
|
||||
"
|
||||
:options="
|
||||
extensionData.client_data.fields.map(f => f.name)
|
||||
"
|
||||
></q-select>
|
||||
</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>Generate Action Button</q-item-label>
|
||||
<q-item-label caption>
|
||||
<ul class="q-pa-none q-ma-none">
|
||||
<li>
|
||||
If enabled, the public page will have a button to
|
||||
perform an action (e.g. generate a payment request).
|
||||
</li>
|
||||
<li>
|
||||
The action will use the selected input fields from
|
||||
<code v-text="extensionData.client_data.name"></code
|
||||
> (Client Data) as parameters.
|
||||
</li>
|
||||
<li>
|
||||
A corresponding REST API endpoint will be created.
|
||||
</li>
|
||||
</ul></q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-toggle
|
||||
v-model="
|
||||
extensionData.public_page.action_fields.generate_action
|
||||
"
|
||||
size="md"
|
||||
color="green"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
</div>
|
||||
<q-separator
|
||||
v-if="extensionData.public_page.action_fields.generate_action"
|
||||
class="q-mt-sm"
|
||||
></q-separator>
|
||||
|
||||
<div v-if="extensionData.public_page.action_fields.generate_action">
|
||||
<div class="row q-col-gutter-md q-mt-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<q-item tag="label" v-ripple>
|
||||
<q-item-section>
|
||||
<q-item-label>Generate Payment Logic</q-item-label>
|
||||
<q-item-label caption>
|
||||
<ul class="q-pa-none q-ma-none">
|
||||
<li>
|
||||
If enabled, the endpoint will create an invoice from
|
||||
the submitted data and the UI will show the QR code
|
||||
with the invoice.
|
||||
</li>
|
||||
<li>
|
||||
A listener will be created to check for the pay
|
||||
event.
|
||||
</li>
|
||||
<li>You must map the fieds.</li>
|
||||
</ul></q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-toggle
|
||||
v-model="
|
||||
extensionData.public_page.action_fields
|
||||
.generate_payment_logic
|
||||
"
|
||||
size="md"
|
||||
color="green"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-6"></div>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
extensionData.public_page.action_fields.generate_action &&
|
||||
extensionData.public_page.action_fields.generate_payment_logic
|
||||
"
|
||||
class="row q-col-gutter-md q-mt-md"
|
||||
>
|
||||
<div class="col-12 col-md-6">
|
||||
<q-item tag="label" v-ripple>
|
||||
<q-item-section>
|
||||
<q-item-label>Wallet</q-item-label>
|
||||
<q-item-label caption>
|
||||
<ul class="q-pa-none q-ma-none">
|
||||
<li>
|
||||
Select the field from the
|
||||
<code v-text="extensionData.owner_data.name"></code
|
||||
> (Owner Data) that represents the wallet
|
||||
which will generate the invoice and receive the
|
||||
payments.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
Only fields with the type <code>Wallet</code> will
|
||||
be shown.
|
||||
</li>
|
||||
</ul>
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="
|
||||
extensionData.public_page.action_fields.wallet_id
|
||||
"
|
||||
:options="
|
||||
[''].concat(
|
||||
extensionData.owner_data.fields
|
||||
.filter(f => f.type === 'wallet')
|
||||
.map(f => f.name)
|
||||
)
|
||||
"
|
||||
></q-select>
|
||||
</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>Currency</q-item-label>
|
||||
<q-item-label caption>
|
||||
<ul class="q-pa-none q-ma-none">
|
||||
<li>
|
||||
Select the field from the
|
||||
<code v-text="extensionData.owner_data.name"></code
|
||||
> (Owner Data) that represents the currency
|
||||
which will be used to for the amount.
|
||||
</li>
|
||||
<li>
|
||||
Only fields with the type <code>Currency</code> will
|
||||
be shown.
|
||||
</li>
|
||||
<li>Empty if you want to use sats.</li>
|
||||
</ul>
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="
|
||||
extensionData.public_page.action_fields.currency
|
||||
"
|
||||
:options="
|
||||
[''].concat(
|
||||
extensionData.owner_data.fields
|
||||
.filter(f => f.type === 'currency')
|
||||
.map(f => f.name)
|
||||
)
|
||||
"
|
||||
></q-select>
|
||||
</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>Amount</q-item-label>
|
||||
<q-item-label caption>
|
||||
<ul class="q-pa-none q-ma-none">
|
||||
<li>
|
||||
Select the field from the
|
||||
<code v-text="extensionData.owner_data.name"></code
|
||||
> (Owner Data) or
|
||||
<code v-text="extensionData.client_data.name"></code
|
||||
> (Client Data) that represents the amount (in
|
||||
the selected currency).
|
||||
</li>
|
||||
<li>
|
||||
Only fields with the type <code>Integer</code> and
|
||||
<code>Float</code> will be shown.
|
||||
</li>
|
||||
</ul>
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="
|
||||
extensionData.public_page.action_fields
|
||||
.amount_source
|
||||
"
|
||||
:options="amountSource"
|
||||
class="q-mr-sm"
|
||||
></q-select>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="
|
||||
extensionData.public_page.action_fields.amount
|
||||
"
|
||||
:options="paymentActionAmountFields"
|
||||
></q-select>
|
||||
</div>
|
||||
</div>
|
||||
</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>Paid Flag</q-item-label>
|
||||
<q-item-label caption>
|
||||
<ul class="q-pa-none q-ma-none">
|
||||
<li>
|
||||
Select the field from the
|
||||
<code v-text="extensionData.client_data.name"></code
|
||||
> (Client Data) that will be set to true when
|
||||
the invoice is paid.
|
||||
</li>
|
||||
<li>
|
||||
Only fields with the type <code>Boolean</code> will
|
||||
be shown.
|
||||
</li>
|
||||
</ul>
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="
|
||||
extensionData.public_page.action_fields.paid_flag
|
||||
"
|
||||
:options="
|
||||
[''].concat(
|
||||
extensionData.client_data.fields
|
||||
.filter(f => f.type === 'bool')
|
||||
.map(f => f.name)
|
||||
)
|
||||
"
|
||||
></q-select>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</q-step>
|
||||
|
||||
<q-step
|
||||
:name="6"
|
||||
:done="step > 6"
|
||||
title="Publish"
|
||||
icon="publish"
|
||||
style="min-height: 100px"
|
||||
>
|
||||
<div v-if="g.user.admin" class="row">
|
||||
<div class="col-md-4 col-sm-12 col-xs-12">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
v-model="extensionData.stub_version"
|
||||
hint="The version of the extension stub. Make sure it is compatible with your LNbits install."
|
||||
:options="extensionStubVersions.map(f => f.version)"
|
||||
></q-select>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-12 col-xs-12">
|
||||
<q-btn
|
||||
@click="cleanCacheData()"
|
||||
color="grey"
|
||||
outline
|
||||
label="Clean Cache"
|
||||
class="q-ml-md"
|
||||
/>
|
||||
<q-icon
|
||||
name="info"
|
||||
size="md"
|
||||
color="primary"
|
||||
class="cursor-pointer q-ml-xs q-mb-xs"
|
||||
>
|
||||
<q-tooltip>
|
||||
<ul class="q-pl-sm">
|
||||
<li>
|
||||
The extension builder uses caching to speed up the build
|
||||
process.
|
||||
</li>
|
||||
<li>
|
||||
This action clears old data and redownloads the Extension
|
||||
Builder Stub release.
|
||||
</li>
|
||||
</ul>
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="g.user.admin" class="row q-mt-md">
|
||||
<div class="col-md-4 col-sm-12 col-xs-12">
|
||||
<div class="row">
|
||||
<q-btn
|
||||
@click="buildExtensionAndDeploy()"
|
||||
color="primary"
|
||||
label="Build and Deploy (Admin Only)"
|
||||
class="col"
|
||||
/>
|
||||
<q-icon
|
||||
name="info"
|
||||
size="md"
|
||||
color="primary"
|
||||
class="cursor-pointer q-ml-sm self-center"
|
||||
>
|
||||
<q-tooltip>
|
||||
<ul class="q-pl-sm">
|
||||
<li>
|
||||
Installs the extension directly to this LNbits instance.
|
||||
</li>
|
||||
<li>
|
||||
The extension will be enabled by default, and available
|
||||
to all users.
|
||||
</li>
|
||||
</ul>
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row q-mt-md">
|
||||
<div class="col-md-4 col-sm-12 col-xs-12">
|
||||
<div class="row">
|
||||
<q-btn
|
||||
@click="buildExtension()"
|
||||
outline
|
||||
color="gray"
|
||||
label="Download Extension Zip"
|
||||
icon="download"
|
||||
class="col"
|
||||
/>
|
||||
<q-icon
|
||||
name="info"
|
||||
size="md"
|
||||
color="primary"
|
||||
class="cursor-pointer q-ml-sm self-center"
|
||||
>
|
||||
<q-tooltip>
|
||||
Builds the extension and downloads a zip file with the code.
|
||||
You can then install it manually in your LNbits instance.
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</q-step>
|
||||
|
||||
<template v-slot:navigation>
|
||||
<q-separator></q-separator>
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-sm-12 q-pl-md q-pt-md">
|
||||
<q-btn
|
||||
v-if="step == 1"
|
||||
label="Clear All Data"
|
||||
color="negative"
|
||||
@click="clearAllData"
|
||||
></q-btn>
|
||||
<q-btn
|
||||
v-else
|
||||
flat
|
||||
color="grey-8"
|
||||
class="q-mr-sm"
|
||||
@click="previousStep()"
|
||||
label="Back"
|
||||
icon="chevron_left"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-12 q-pr-md q-pb-md">
|
||||
<q-stepper-navigation class="float-right">
|
||||
<q-btn
|
||||
v-if="step < 6"
|
||||
@click="nextStep()"
|
||||
color="primary"
|
||||
label="Next"
|
||||
></q-btn>
|
||||
<template v-else>
|
||||
<q-btn
|
||||
@click="exportJsonData()"
|
||||
color="primary"
|
||||
label="Export JSON Data"
|
||||
></q-btn>
|
||||
<q-icon
|
||||
name="info"
|
||||
size="md"
|
||||
color="primary"
|
||||
class="cursor-pointer q-ml-sm self-center"
|
||||
>
|
||||
<q-tooltip>
|
||||
<ul class="q-pl-sm">
|
||||
<li>
|
||||
Exports the config JSON so it can be later imported or
|
||||
shared.
|
||||
</li>
|
||||
<li>
|
||||
This JSON is also added to the zip in a file called
|
||||
`builder.json`.
|
||||
</li>
|
||||
</ul>
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</template>
|
||||
</q-stepper-navigation>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</q-stepper>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-col-gutter-md"></div>
|
||||
</template>
|
||||
|
|
@ -95,6 +95,7 @@
|
|||
"js/lnurl.js"
|
||||
],
|
||||
"components": [
|
||||
"js/pages/extensions_builder.js",
|
||||
"js/pages/payments.js",
|
||||
"js/pages/node.js",
|
||||
"js/pages/node-public.js",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue