Files
lnbits/lnbits/templates/pages/extensions.vue
T

1317 lines
44 KiB
Vue

<template id="page-extensions">
<div class="row q-col-gutter-md q-mb-md">
<div class="col-12">
<q-card>
<div>
<div class="q-gutter-y-md">
<q-tabs v-model="tab" active-color="primary" align="left">
<q-tab name="installed" :label="$t('installed')"></q-tab>
<q-tab name="all" :label="$t('all')"></q-tab>
<q-tab name="featured" :label="$t('featured')"></q-tab>
<i
v-if="!g.user.admin && tab != 'installed'"
v-text="$t('only_admins_can_install')"
></i>
<q-space></q-space>
<q-input
v-if="$q.screen.gt.sm"
:label="$t('search_extensions')"
:dense="dense"
class="float-right q-pr-xl"
v-model="searchTerm"
>
<template v-slot:before>
<q-icon name="search"> </q-icon>
</template>
<template v-slot:append>
<q-icon
v-if="searchTerm !== ''"
name="close"
@click="searchTerm = ''"
class="cursor-pointer"
>
</q-icon>
</template>
</q-input>
<q-btn
v-else
flat
icon="search"
@click="searchToggle = !searchToggle"
class="q-mr-md"
>
</q-btn>
<q-badge
v-if="g.user.admin && updatableExtensions?.length"
@click="showUpdateAllDialog = true"
color="primary"
class="float-right q-pa-sm q-mr-md cursor-pointer"
>
<span
v-text="
$t('new_version') + ` (${updatableExtensions?.length})`
"
></span>
</q-badge>
<q-btn
v-if="extbuilderEnabled"
flat
no-caps
icon="architecture"
to="/extensions/builder"
><span v-text="$t('create_extension')"></span
></q-btn>
<q-btn v-else disabled flat no-caps icon="architecture"
><span v-text="$t('create_extension')"></span>
<q-tooltip
v-text="$t('only_admins_can_create_extensions')"
></q-tooltip>
</q-btn>
<q-btn
v-if="g.user.admin"
flat
round
icon="settings"
to="/admin#extensions"
><q-tooltip v-text="$t('admin_settings')"></q-tooltip
></q-btn>
</q-tabs>
<div v-if="$q.screen.lt.sm && searchToggle" class="q-pa-sm">
<q-input
:label="$t('search_extensions')"
dense
class=""
v-model="searchTerm"
autofocus
>
<template v-slot:append>
<q-icon
v-if="searchTerm !== ''"
name="close"
@click="searchTerm = ''"
class="cursor-pointer"
>
</q-icon>
</template>
</q-input>
</div>
</div>
</div>
</q-card>
</div>
</div>
<div class="row q-col-gutter-md">
<div
v-if="filteredExtensions"
class="col-12 col-sm-6 col-md-6 col-lg-4"
v-for="extension in filteredExtensions"
:key="extension.id + extension.hash"
>
<q-card>
<q-card-section>
<div class="row">
<div class="col-3">
<q-img
@click="
showExtensionDetails(extension.id, extension.details_link)
"
v-if="extension.icon"
:src="extension.icon"
spinner-color="white"
style="cursor: pointer; max-width: 100%"
>
<q-tooltip>
<span v-text="extension.shortDescription"></span>
</q-tooltip>
</q-img>
<div v-else>
<q-icon
class="gt-sm"
name="extension"
color="primary"
size="70px"
></q-icon>
<q-icon
class="lt-md"
name="extension"
color="primary"
size="35px"
></q-icon>
</div>
</div>
<div class="col-9 q-pl-md">
<q-badge
v-if="extension.isInstalled"
@click="showManageExtension(extension)"
class="float-right"
color="transparent"
style="cursor: pointer"
>
<span v-text="extension.installedRelease.version"></span>
<q-tooltip
><span v-text="extension.installedRelease.version"></span
></q-tooltip>
</q-badge>
<div
v-if="extension.name"
class="text-h5"
style="cursor: pointer"
@click="
showExtensionDetails(extension.id, extension.details_link)
"
v-text="extension.name"
></div>
<div style="justify-content: space-between; display: flex">
<lnbits-extension-rating
:rating="
formatAvg(
extension.reviewStats
? extension.reviewStats.avg_rating
: 0
)
"
:count="
extension.reviewStats
? extension.reviewStats.review_count
: null
"
:clickable="!!reviewsUrl"
@click="openReviews(extension)"
></lnbits-extension-rating>
<q-btn-group size="xs" style="margin: 5px 0">
<q-btn
v-if="extension.hasFreeRelease"
color="green"
size="xs"
:label="$t('free')"
>
<q-tooltip>
<span v-text="$t('extension_has_free_release')"></span>
</q-tooltip>
</q-btn>
<q-btn
v-if="extension.hasPaidRelease || extension.paidFeatures"
color="primary"
size="xs"
:label="$t('paid')"
>
<q-tooltip>
<span
v-if="extension.hasPaidRelease"
v-text="$t('extension_has_paid_release')"
></span>
<br
v-if="
extension.hasPaidRelease && extension.paidFeatures
"
/>
<span
v-if="extension.paidFeatures"
v-text="extension.paidFeatures"
></span>
</q-tooltip>
</q-btn>
</q-btn-group>
</div>
<div style="justify-content: space-between; display: flex">
<q-toggle
size="xs"
v-if="
extension.isAvailable &&
extension.isInstalled &&
g.user.admin
"
:label="
extension.isActive ? $t('activated') : $t('deactivated')
"
color="secondary"
v-model="extension.isActive"
@update:model-value="toggleExtension(extension)"
><q-tooltip>
&nbsp;
<span
v-text="$t('activate_extension_details')"
></span> </q-tooltip
></q-toggle>
<q-badge
v-if="hasNewVersion(extension)"
@click="showManageExtension(extension)"
color="primary"
class="float-right"
style="cursor: pointer; margin: 5px 0"
>
<span v-text="$t('new_version')"></span>
<q-tooltip
><span v-text="extension.latestRelease.version"></span
></q-tooltip>
</q-badge>
</div>
<div>
<p
style="
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
"
v-text="extension.shortDescription"
></p>
<q-tooltip
><span v-text="extension.shortDescription"></span
></q-tooltip>
</div>
</div>
</div>
<div
id="dependencies"
class="row q-pt-sm"
v-if="extension.dependencies?.length"
>
<div class="col">
<small v-text="$t('extension_depends_on')"></small>
<q-badge
v-for="dep in extension.dependencies"
:key="dep"
color="orange"
>
<small v-text="dep"></small>
</q-badge>
</div>
</div>
</q-card-section>
<q-separator></q-separator>
<q-card-actions style="min-height: 52px">
<div class="col-10">
<div v-if="!extension.inProgress">
<q-btn
v-if="
g.user.extensions.includes(extension.id) &&
extension.isActive &&
extension.isInstalled
"
flat
color="primary"
type="a"
:href="extension.id + '/'"
:label="$t('open')"
></q-btn>
<q-btn
v-if="
g.user.extensions.includes(extension.id) &&
extension.isActive &&
extension.isInstalled
"
flat
color="grey-5"
@click="disableExtension(extension)"
:label="$t('disable')"
></q-btn>
<q-badge
v-if="extension.isAdminOnly && !g.user.admin"
v-text="$t('admin_only')"
>
</q-badge>
<q-btn
v-else-if="
extension.isInstalled &&
extension.isActive &&
!g.user.extensions.includes(extension.id)
"
flat
color="primary"
@click="enableExtensionForUser(extension)"
:label="
$t(extension.isPaymentRequired ? 'pay_to_enable' : 'enable')
"
>
<q-tooltip>
<span v-text="$t('enable_extension_details')">
</span> </q-tooltip
></q-btn>
<q-btn
@click="showManageExtension(extension)"
flat
color="primary"
v-if="g.user.admin"
:label="$t('manage')"
><q-tooltip
><span v-text="$t('manage_extension_details')"></span
></q-tooltip>
</q-btn>
</div>
<div v-else>
<q-spinner-bars color="primary" size="2.55em"></q-spinner-bars>
</div>
</div>
<div class="col-2">
<div v-if="extension.details_link" class="float-right">
<q-btn
@click="
showExtensionDetails(extension.id, extension.details_link)
"
flat
:label="$t('more')"
>
<q-tooltip>
<span v-text="extension.shortDescription"></span>
</q-tooltip>
</q-btn>
</div>
</div>
</q-card-actions>
</q-card>
</div>
</div>
<q-dialog v-model="showUninstallDialog" position="top">
<q-card class="q-pa-lg">
<h6 class="q-my-md text-primary" v-text="$t('warning')"></h6>
<p>
<span v-text="$t('extension_uninstall_warning')"></span><br />
<span v-text="$t('confirm_continue')"></span>
</p>
<div class="row q-mt-lg">
<q-checkbox
v-model="uninstallAndDropDb"
value="false"
label="Cleanup database tables"
>
<q-tooltip class="bg-grey-8" anchor="bottom left" self="top left"
><span v-text="$t('extension_db_drop_info')"></span>
</q-tooltip>
</q-checkbox>
</div>
<div class="row q-mt-lg">
<q-btn
outline
color="grey"
@click="uninstallExtension()"
v-text="$t('uninstall_confirm')"
></q-btn>
<q-btn
v-close-popup
flat
color="grey"
class="q-ml-auto"
v-text="$t('cancel')"
></q-btn>
</div>
</q-card>
</q-dialog>
<q-dialog v-model="showDropDbDialog" position="top">
<q-card v-if="selectedExtension" class="q-pa-lg">
<h6 class="q-my-md text-primary" v-text="$t('warning')"></h6>
<p><span v-text="$t('extension_db_drop_warning')"></span><br /></p>
<q-input
v-model="dropDbExtensionId"
:label="selectedExtension.id"
></q-input>
<br />
<p v-text="$t('confirm_continue')"></p>
<div class="row q-mt-lg">
<q-btn
:disable="dropDbExtensionId !== selectedExtension.id"
outline
color="red"
@click="dropExtensionDb()"
v-text="$t('confirm')"
></q-btn>
<q-btn
v-close-popup
flat
color="grey"
class="q-ml-auto"
v-text="$t('cancel')"
></q-btn>
</div>
</q-card>
</q-dialog>
<q-dialog v-model="showManageExtensionDialog" position="top">
<q-card v-if="selectedRelease" class="q-pa-lg lnbits__dialog-card">
<q-card-section>
<div v-if="selectedRelease.paymentRequest">
<lnbits-qrcode
:value="'LIGHTNING:' + selectedRelease.paymentRequest.toUpperCase()"
:href="'lightning:' + selectedRelease.paymentRequest"
></lnbits-qrcode>
</div>
<div v-else>
<q-spinner-bars color="primary" size="2.55em"></q-spinner-bars>
</div>
</q-card-section>
<div class="row q-mt-lg">
<div class="col">
<q-btn
v-if="selectedRelease.paymentRequest"
outline
color="grey"
@click="utils.copyText(selectedRelease.paymentRequest)"
:label="$t('copy_invoice')"
></q-btn>
</div>
<div class="col">
<q-btn
v-close-popup
flat
color="grey"
class="float-right q-ml-lg"
v-text="$t('close')"
></q-btn>
</div>
</div>
</q-card>
<q-card v-else class="q-pa-lg lnbits__dialog-card">
<q-tabs
v-model="manageExtensionTab"
active-color="primary"
align="justify"
>
<q-tab
name="releases"
:label="$t('releases')"
@update="val => (manageExtensionTab = val.name)"
></q-tab>
<q-tab
v-if="selectedExtension && selectedExtension.isInstalled"
name="sell"
:label="$t('sell')"
@update="val => (manageExtensionTab = val.name)"
></q-tab>
</q-tabs>
<div
v-show="manageExtensionTab === 'releases'"
class="col-12 col-md-5 q-gutter-y-md q-mt-md"
v-if="selectedExtensionRepos"
>
<q-card
flat
bordered
class="my-card"
v-for="repoName of Object.keys(selectedExtensionRepos)"
:key="repoName"
>
<q-expansion-item
:key="repoName"
group="repos"
:caption="repoName"
:content-inset-level="0.5"
:default-opened="selectedExtensionRepos[repoName].isInstalled"
>
<template v-slot:header>
<q-item-section avatar>
<q-avatar
:icon="
selectedExtensionRepos[repoName].isInstalled
? 'download_done'
: 'download'
"
:text-color="
selectedExtensionRepos[repoName].isInstalled ? 'green' : ''
"
/>
</q-item-section>
<q-item-section>
<div class="row">
<div class="col-10">
<span v-text="$t('repository')"></span>
<br />
<small v-text="repoName"></small>
<q-tooltip
><span
v-text="selectedExtensionRepos[repoName].repo"
></span
></q-tooltip>
</div>
<div class="col-2"></div>
</div>
</q-item-section>
</template>
<q-card-section class="q-pa-none">
<q-separator></q-separator>
<q-list>
<q-expansion-item
v-for="release of selectedExtensionRepos[repoName].releases"
:key="release.version"
group="releases"
@click="getGitHubReleaseDetails(release)"
:icon="getReleaseIcon(release)"
:label="release.description"
:caption="release.version"
:content-inset-level="0.5"
:header-class="getReleaseIconColor(release)"
>
<div v-if="release.inProgress">
<q-spinner-bars
color="primary"
size="2.55em"
></q-spinner-bars>
</div>
<div v-else-if="release.error">
<q-icon
class="gt-sm"
name="error"
color="pink"
size="70px"
></q-icon>
<span v-text="$t('release_details_error')"></span>
</div>
<q-card class="no-border" v-else>
<q-card-section v-if="release.is_version_compatible">
<span
v-if="release.requiresPayment && !release.paid_sats"
v-text="$t('extension_cost', {cost: release.cost_sats})"
class="q-mb-lg"
></span>
<span
v-if="release.requiresPayment && release.paid_sats"
class="q-mb-lg"
v-text="
$t('extension_paid_sats', {
paid_sats: release.paid_sats
})
"
></span>
<div
v-if="
!release.requiresPayment ||
(release.requiresPayment && release.paid_sats)
"
>
<q-btn
v-if="!release.isInstalled"
@click="installExtension(release)"
color="primary unelevated mt-lg pt-lg"
:label="$t('install')"
></q-btn>
</div>
<div v-if="release.requiresPayment && !release.paid_sats">
<div v-if="!release.payment_hash">
<q-input
filled
dense
v-model.number="release.paidAmount"
type="number"
:min="release.cost_sats"
suffix="sat"
class="q-mt-sm"
>
</q-input>
<q-select
filled
dense
emit-value
map-options
v-model="release.wallet"
:options="g.user.walletOptions"
:label="$t('wallet_required')"
class="q-mt-sm"
>
</q-select>
<q-btn
unelevated
color="primary"
@click="payAndInstall(release)"
:disabled="!release.wallet"
class="q-mt-sm"
:label="$t('pay_from_wallet')"
></q-btn>
<q-btn
unelevated
color="primary"
@click="showInstallQRCode(release)"
class="q-mt-sm float-right"
:label="$t('show_qr')"
></q-btn>
</div>
<div v-else>
<br />
<span
class="q-mb-lg q-mt-lg"
v-text="
'There is a previous pending invoice for this release.'
"
></span>
<br />
<q-btn
unelevated
@click="installExtension(release)"
color="primary"
class="q-mt-sm"
:label="$t('retry_install')"
></q-btn>
<q-btn
unelevated
@click="clearHangingInvoice(release)"
color="primary"
class="q-mt-sm float-right"
:label="$t('new_payment')"
></q-btn>
</div>
</div>
<div>
<q-btn
v-if="release.isInstalled"
@click="showUninstall()"
:label="$t('uninstall')"
flat
color="red"
></q-btn>
</div>
<a
v-if="release.html_url"
class="text-secondary float-right"
:href="release.html_url"
target="_blank"
rel="noopener noreferrer"
style="color: inherit"
v-text="$t('release_notes')"
></a>
</q-card-section>
<q-card-section v-else>
<span
v-text="$t('extension_required_lnbits_version')"
></span>
<span class="q-mr-sm">:</span>
<ul>
<li v-if="release.min_lnbits_version">
<span v-text="$t('min_version')"></span>
<span class="q-mr-sm">:</span>
<strong>
<span v-text="release.min_lnbits_version"></span>
</strong>
</li>
<li v-if="release.max_lnbits_version">
<span v-text="$t('max_version')"></span>
<span class="q-mr-sm">:</span>
<strong>
<span v-text="release.max_lnbits_version"></span>
</strong>
</li>
</ul>
</q-card-section>
<q-card v-if="release.warning">
<q-card-section>
<div class="text-h6">
<q-badge
color="yellow"
text-color="black"
v-text="$t('warning')"
>
</q-badge>
</div>
<div class="text-subtitle2">
<span v-text="release.warning"></span>
</div>
</q-card-section>
</q-card>
<q-separator></q-separator> </q-card
></q-expansion-item>
</q-list>
</q-card-section>
</q-expansion-item>
</q-card>
<div class="row q-mt-lg">
<q-btn
v-if="selectedExtension?.isInstalled"
@click="showUninstall()"
flat
color="red"
v-text="$t('uninstall')"
></q-btn>
<q-btn
v-else-if="selectedExtension?.hasDatabaseTables"
@click="showDropDb()"
flat
color="red"
:label="$t('drop_db')"
></q-btn>
<q-btn
v-close-popup
flat
color="grey"
class="q-ml-auto"
v-text="$t('close')"
></q-btn>
</div>
</div>
<q-spinner-bars v-else color="primary" size="2.55em"></q-spinner-bars>
<div
v-if="selectedExtension"
v-show="manageExtensionTab === 'sell'"
class="col-12 col-md-5 q-gutter-y-md q-mt-md"
>
<q-toggle
v-model="selectedExtension.payToEnable.required"
:label="$t('sell_require')"
color="secondary"
style="max-height: 21px"
></q-toggle>
<q-select
v-if="selectedExtension.payToEnable.required"
filled
dense
emit-value
map-options
v-model="selectedExtension.payToEnable.wallet"
:options="g.user.walletOptions"
label="Wallet *"
class="q-mt-md"
></q-select>
<q-input
v-if="selectedExtension.payToEnable.required"
filled
dense
v-model.number="selectedExtension.payToEnable.amount"
:label="$t('amount_sats')"
type="number"
min="1"
class="q-mt-md"
>
</q-input>
<div class="row q-mt-lg">
<q-btn
@click="updatePayToInstallData(selectedExtension)"
flat
color="green"
v-text="$t('update_payment')"
></q-btn>
<q-btn
v-close-popup
flat
color="grey"
class="q-ml-auto"
v-text="$t('close')"
></q-btn>
</div>
</div>
</q-card>
</q-dialog>
<q-dialog v-model="showPayToEnableDialog" position="top">
<q-card v-if="selectedExtension" class="q-pa-md">
<q-card-section>
<p>
<span
v-text="
$t('sell_info', {
name: selectedExtension.name,
amount: selectedExtension.payToEnable.amount
})
"
></span>
</p>
<p>
<span v-text="$t('already_paid_question')"></span>
<q-badge
@click="enableExtension(selectedExtension)"
color="primary"
class="cursor-pointer"
rounded
>
<strong> <span v-text="$t('recheck')"></span> </strong
></q-badge>
</p>
</q-card-section>
<q-card-section v-if="selectedExtension.payToEnable.showQRCode">
<div class="row q-mt-lg">
<div v-if="selectedExtension.payToEnable.paymentRequest" class="col">
<lnbits-qrcode
:value="
'LIGHTNING:' +
selectedExtension.payToEnable.paymentRequest.toUpperCase()
"
:href="
'lightning:' + selectedExtension.payToEnable.paymentRequest
"
></lnbits-qrcode>
</div>
<div v-else class="col">
<q-spinner-bars color="primary" size="2.55em"></q-spinner-bars>
</div>
</div>
<div class="row q-mt-lg">
<div class="col">
<q-btn
v-if="selectedExtension.payToEnable.paymentRequest"
outline
color="grey"
@click="
utils.copyText(selectedExtension.payToEnable.paymentRequest)
"
:label="$t('copy_invoice')"
></q-btn>
</div>
<div class="col">
<q-btn
v-close-popup
flat
color="grey"
class="float-right q-ml-lg"
v-text="$t('close')"
></q-btn>
</div>
</div>
</q-card-section>
<q-card-section v-else>
<div class="row q-mt-lg">
<div class="col">
<div>
<q-input
filled
dense
type="number"
v-model.number="selectedExtension.payToEnable.paidAmount"
:min="selectedExtension.payToEnable.amount"
suffix="sat"
class="q-mt-sm"
>
</q-input>
<q-select
filled
dense
v-model="selectedExtension.payToEnable.paymentWallet"
emit-value
map-options
:options="g.user.walletOptions"
:label="$t('wallet_required')"
class="q-mt-sm"
>
</q-select>
<q-separator class="q-mb-lg"></q-separator>
<q-btn
unelevated
color="primary"
class="q-mt-sm"
@click="payAndEnable(selectedExtension)"
:disabled="!selectedExtension.payToEnable.paymentWallet"
:label="$t('pay_from_wallet')"
></q-btn>
<q-btn
unelevated
@click="showEnableQRCode(selectedExtension)"
color="primary"
class="q-mt-sm float-right"
:label="$t('show_qr')"
></q-btn>
</div>
</div>
</div>
</q-card-section>
</q-card>
</q-dialog>
<q-dialog v-model="showExtensionDetailsDialog" position="top">
<q-card
v-if="selectedExtensionDetails"
class="q-pa-sm"
style="width: 800px; max-width: 95vw"
>
<q-card-section>
<div class="row">
<div class="col-2 gt-md">
<q-img
:src="selectedExtensionDetails.icon"
style="width: 100px"
type="image"
></q-img>
</div>
<div class="col-9 q-pl-md gt-xs">
<h3 class="q-my-sm" v-text="selectedExtensionDetails.name"></h3>
<h6
class="q-my-sm"
v-text="selectedExtensionDetails.short_description"
></h6>
</div>
<div class="col-9 q-pl-md lt-sm">
<h5 class="q-my-sm" v-text="selectedExtensionDetails.name"></h5>
<p
class="q-my-sm"
v-text="selectedExtensionDetails.short_description"
></p>
</div>
<div class="col-1">
<q-btn
v-close-popup
flat
color="grey"
class="float-right q-ml-lg"
v-text="$t('close')"
></q-btn>
</div>
</div>
<div v-if="selectedExtensionDetails.images?.length" class="row q-my-lg">
<div class="col q-pr-md">
<q-carousel
navigation-position="top"
swipeable
animated
v-model="slide"
v-model:fullscreen="fullscreen"
thumbnails
infinite
:autoplay="autoplay"
arrows
transition-prev="slide-right"
transition-next="slide-left"
@mouseenter="autoplay = false"
@mouseleave="autoplay = true"
height="300px"
>
<template v-slot:control>
<q-carousel-control position="bottom-right" :offset="[18, 18]">
<q-btn
push
round
dense
color="white"
text-color="primary"
:icon="fullscreen ? 'fullscreen_exit' : 'fullscreen'"
@click="fullscreen = !fullscreen"
></q-btn>
</q-carousel-control>
</template>
<q-carousel-slide
v-for="(image, i) of selectedExtensionDetails.images"
:img-src="image.uri"
:key="i"
:name="i"
>
<q-video
v-if="image.link"
class="absolute-full"
:src="image.link"
/>
</q-carousel-slide>
</q-carousel>
</div>
</div>
<div class="row">
<div class="col-sm-12 col-md-8 q-pr-sm">
<div v-html="selectedExtensionDetails.description_md"></div>
</div>
<div class="col-sm-12 col-md-4 q-pl-sm">
<lnbits-extension-rating
:rating="
formatAvg(
selectedExtension && selectedExtension.reviewStats
? selectedExtension.reviewStats.avg_rating
: 0
)
"
:count="
selectedExtension && selectedExtension.reviewStats
? selectedExtension.reviewStats.review_count
: null
"
:clickable="!!reviewsUrl"
@click="openReviews(selectedExtension)"
></lnbits-extension-rating>
<div class="q-mt-md">
<b>
<span v-text="$t('contributors')"></span>
</b>
<small>
<div
v-for="contributor of selectedExtensionDetails.contributors"
>
<a
:href="contributor.uri"
target="_blank"
rel="noopener noreferrer"
style="color: var(--q-primary); text-decoration: none"
>
<span
v-text="
(contributor.name || contributor) +
' - ' +
(contributor.role || 'dev')
"
></span>
</a>
</div>
</small>
</div>
<div class="q-pt-md">
<div>
<q-btn
size="sm"
color="primary"
label="Repo"
type="a"
:href="selectedExtensionDetails.repo"
target="_blank"
rel="noopener noreferrer"
><q-tooltip>repository</q-tooltip></q-btn
>
</div>
<div class="q-pt-lg">
<div>
<b>
<span v-text="$t('license')"></span>
</b>
<q-badge
color="primary"
v-text="selectedExtensionDetails.license"
></q-badge>
</div>
<br />
</div>
</div>
</div>
</div>
</q-card-section>
</q-card>
</q-dialog>
<q-dialog v-model="reviewsDialog.show" position="top">
<q-card
class="q-pa-md lnbits__dialog-card"
style="width: 900px; max-width: 95vw"
>
<q-card-section class="q-gutter-y-sm">
<div class="row items-center">
<div class="col">
<div
class="text-h6"
v-text="
(reviewsDialog.extension && reviewsDialog.extension.name) ||
(reviewsDialog.extension && reviewsDialog.extension.id)
"
></div>
<div
class="text-caption text-grey"
v-text="reviewsDialog.extension && reviewsDialog.extension.id"
></div>
</div>
<div class="col-auto">
<lnbits-extension-rating
:rating="
formatAvg(
reviewsDialog.extension && reviewsDialog.extension.reviewStats
? reviewsDialog.extension.reviewStats.avg_rating
: 0
)
"
:count="
reviewsDialog.extension && reviewsDialog.extension.reviewStats
? reviewsDialog.extension.reviewStats.review_count
: null
"
></lnbits-extension-rating>
</div>
</div>
</q-card-section>
<q-separator></q-separator>
<q-card-section v-if="!reviewsUrl">
<div
class="text-negative"
v-text="$t('reviews_url_not_configured')"
></div>
</q-card-section>
<q-card-section v-else>
<div v-if="reviewsDialog.loading" class="row justify-center q-pa-lg">
<q-spinner-bars color="primary" size="2.55em"></q-spinner-bars>
</div>
<div v-else>
<div v-if="reviewsDialog.error" class="text-negative q-mb-md">
<span v-text="reviewsDialog.error"></span>
</div>
<q-form @submit="submitReview" class="q-gutter-md">
<div class="row q-col-gutter-lg">
<div class="col-12 col-md-6">
<q-input
dense
filled
v-model="reviewsDialog.form.name"
:label="$t('reviews_name')"
></q-input>
</div>
<div class="col-12 col-md-6">
<q-rating
v-model="reviewsDialog.form.rating"
max="10"
icon="star_border"
icon-selected="star"
icon-half="star_half"
color="primary"
class="float-right"
></q-rating>
</div>
<div class="col-12 col-md-6">
<q-input
dense
filled
type="textarea"
autogrow
v-model="reviewsDialog.form.comment"
:label="$t('reviews_comment')"
></q-input>
</div>
<div class="col-12 col-md-6">
<q-btn
type="submit"
color="primary"
class="float-right"
unelevated
:loading="reviewsDialog.submitting"
:disable="!reviewsDialog.form.rating"
:label="$t('reviews_submit')"
></q-btn>
</div>
</div>
</q-form>
<q-separator class="q-my-md"></q-separator>
<div class="row q-col-gutter-lg">
<div class="col-12">
<div v-if="reviews.length === 0" class="text-grey q-mb-md">
<span v-text="$t('no_reviews')"></span>
</div>
<div v-else>
<q-table
:rows="reviews"
:columns="reviewsTable.columns"
v-model:pagination="reviewsTable.pagination"
@request="getTagReviews"
:loading="reviewsTable.loading"
row-key="name"
:filter="reviewsTable.search"
>
<template v-slot:body="props">
<q-tr :props="props">
<q-td key="name" :props="props">
<span v-text="props.row.name"></span>
</q-td>
<q-td key="comment" :props="props">
<span v-text="props.row.comment"></span>
</q-td>
<q-td key="created_at" :props="props">
<span
v-text="formatReviewDate(props.row.created_at)"
></span>
</q-td>
<q-td key="rating" :props="props">
<q-rating
class="float-right q-pt-xs"
readonly
icon="star_border"
icon-selected="star"
icon-half="star_half"
:model-value="formatAvg(props.row.rating)"
size="sm"
color="secondary"
></q-rating>
</q-td>
</q-tr>
</template>
</q-table>
</div>
</div>
</div>
</div>
</q-card-section>
<q-separator v-if="reviews.length"></q-separator>
<q-card-section>
<q-btn
@click="reviewsDialog.show = false"
color="grey"
outline
class="float-right"
:label="$t('close')"
></q-btn>
</q-card-section>
</q-card>
</q-dialog>
<q-dialog v-model="paymentDialog.show" position="top">
<q-card class="q-pa-md lnbits__dialog-card">
<q-card-section>
<lnbits-qrcode
:value="'LIGHTNING:' + paymentDialog.invoice.toUpperCase()"
:href="'lightning:' + paymentDialog.invoice"
></lnbits-qrcode>
</q-card-section>
<q-card-actions align="between">
<q-btn v-close-popup flat color="grey" :label="$t('close')"></q-btn>
</q-card-actions>
</q-card>
</q-dialog>
<q-dialog v-model="showUpdateAllDialog" position="top">
<q-card class="q-pa-md q-pt-md lnbits__dialog-card">
<div class="row">
<div class="col-12">
<h6 class="q-my-md" v-text="$t('update')"></h6>
</div>
</div>
<div v-if="updatableExtensions?.length > 1" class="row">
<div class="col-12">
<q-btn
outline
color="grey"
@click="selectAllUpdatableExtensionss()"
v-text="$t('select_all')"
></q-btn>
</div>
</div>
<q-virtual-scroll :items="updatableExtensions" style="max-height: 400px">
<template v-slot="{item, index}">
<div class="row">
<div class="q-col">
<q-checkbox
v-model="item.selectedForUpdate"
:disable="item.isUpgraded"
value="false"
:label="item.name + ` (v${item.latestRelease?.version})`"
>
<q-spinner-bars
v-if="item.inProgress"
color="primary"
size="1.5em"
class="q-ml-md"
></q-spinner-bars>
</q-checkbox>
</div>
</div>
</template>
</q-virtual-scroll>
<div class="row q-mt-lg">
<q-btn
@click="updateSelectedExtensions()"
outline
color="grey"
v-text="$t('update')"
></q-btn>
<q-btn
v-close-popup
flat
color="grey"
class="q-ml-auto"
v-text="$t('cancel')"
></q-btn>
</div>
</q-card>
</q-dialog>
</template>