updated plugins to have sticky header

This commit is contained in:
Kukks
2023-11-21 08:49:23 +01:00
parent b9876755fd
commit 04c57ddf4a
6 changed files with 212 additions and 155 deletions

View File

@@ -5,18 +5,26 @@
ViewData.SetActivePage("DataErasure", "Data Erasure", "DataErasure");
}
<partial name="_StatusMessage"/>
<form method="post">
<h2 class="mb-4">@ViewData["Title"]</h2>
<div class="sticky-header-setup"></div>
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
<h2 class="mb-0">@ViewData["Title"]</h2>
<div class="d-flex gap-3 mt-3 mt-sm-0">
<div class="alert alert-warning">
<p>
This plugin erases buyer information on your store's invoices based on when they were created. THERE IS NO UNDOING THIS ACTION ONCE IT HAS EXECUTED.
</p>
</div>
<div class="row">
<div class="col-md-10">
<form method="post">
<button name="command" type="submit" value="save" class="btn btn-primary">Submit</button>
</div>
</div>
<partial name="_StatusMessage"/>
<div class="alert alert-warning">
<p>
This plugin erases buyer information on your store's invoices based on when they were created. THERE IS NO UNDOING THIS ACTION ONCE IT HAS EXECUTED.
</p>
</div>
<div class="row">
<div class="col-xl-8 col-xxl-constrain">
<div class="form-group">
<div class="d-flex align-items-center">
<input asp-for="Enabled" type="checkbox" class="btcpay-toggle me-2"/>
@@ -32,7 +40,7 @@
{
<div>Cleared data up to @Model.LastRunCutoff.Value.ToString("g")</div>
}
<button name="command" type="submit" value="save" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
</form>

View File

@@ -14,17 +14,25 @@
.Prepend(new SelectListItem("Any", ""));
}
<partial name="_StatusMessage"/>
<form method="post">
<h2 class="mb-4">@ViewData["Title"]</h2>
<div class="sticky-header-setup"></div>
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
<h2 class="mb-0">@ViewData["Title"]</h2>
<div class="d-flex gap-3 mt-3 mt-sm-0">
<div class="alert alert-warning mb-4" role="alert">
If you are enabling FixedFloat support, we advise that you configure the invoice expiration to a minimum of 30 minutes as it may take longer than the default 15 minutes to convert the funds.
</div>
<button name="command" type="submit" value="save" class="btn btn-primary">Save</button>
</div>
</div>
<div class="row">
<div class="col-md-10">
<form method="post">
<partial name="_StatusMessage"/>
<div class="alert alert-warning mb-4" role="alert">
If you are enabling FixedFloat support, we advise that you configure the invoice expiration to a minimum of 30 minutes as it may take longer than the default 15 minutes to convert the funds.
</div>
<div class="row">
<div class="col-xl-8 col-xxl-constrain">
<div class="form-group">
<div class="d-flex align-items-center">
<input asp-for="Enabled" type="checkbox" class="btcpay-toggle me-2"/>
@@ -39,14 +47,13 @@
<label asp-for="ExplicitMethods" class="form-label" data-required>Show these conversion options as individual payment methods</label>
<select style="min-height: 300px;" multiple asp-for="ExplicitMethods" asp-items="@FixedFloatSettings.AllowedSendingOptionsList" class="form-select"></select>
</div>
<div class="form-group">
<div class="d-flex align-items-center">
<input asp-for="OnlyShowExplicitMethods" type="checkbox" class="btcpay-toggle me-2"/>
<label asp-for="OnlyShowExplicitMethods" class="form-label mb-0 me-1">Only show explicit methods</label>
</div>
</div>
<button name="command" type="submit" value="save" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
</form>

View File

@@ -8,15 +8,28 @@
ViewData.SetActivePage("Nostr", "Nostr", "Nostr");
}
<partial name="_StatusMessage"/>
<form method="post">
<h2 class="mb-4">@ViewData["Title"]</h2>
<div class="sticky-header-setup"></div>
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
<h2 class="mb-0">@ViewData["Title"]</h2>
<div class="d-flex gap-3 mt-3 mt-sm-0">
<button name="command" type="submit" value="save" class="btn btn-primary">Submit</button>
<button name="command" type="button" class="btn btn-primary" style="display: none" id="import">Import wth Nostr extension</button>
@if (!string.IsNullOrEmpty(Model.Name))
{
<button name="command" type="submit" value="remove" class="btn btn-danger">Clear</button>
}
</div>
</div>
<p class="alert alert-info">For Zaps, just <a class="alert-link" asp-action="EditLightningAddress" asp-controller="UILNURL" asp-route-storeId="@ScopeProvider.GetCurrentStoreId()">enable a lightning address</a>. None of the nostr settings on this page are needed for zaps anymore.</p>
<div class="row">
<div class="col-md-10">
<form method="post">
<partial name="_StatusMessage"/>
<p class="alert alert-info">For Zaps, just <a class="alert-link" asp-action="EditLightningAddress" asp-controller="UILNURL" asp-route-storeId="@ScopeProvider.GetCurrentStoreId()">enable a lightning address</a>. None of the nostr settings on this page are needed for zaps anymore.</p>
<div class="row">
<div class="col-xl-8 col-xxl-constrain">
<div class="form-group">
<div class="form-group pt-2">
<label asp-for="Name" class="form-label"></label>
@@ -32,7 +45,7 @@
<input asp-for="PubKey" class="form-control"/>
<span asp-validation-for="PubKey" class="text-danger"></span>
<p class="text-muted pt-2">Supports hex, npub or nprofile. Will be converted to hex once saved. If nprofile is provided, the relays will be added as well.</p>
</div>
<div class="form-group">
<label asp-for="PrivateKey" class="form-label">Private key for zaps</label>
@@ -67,20 +80,19 @@
}
}
</tbody>
<tfoot>
<tr>
<td colspan="2">
<button type="button" id="add-relay" class="btn btn-link w-100">Add Relay</button>
</td>
</tr>
</tfoot>
</table>
<div class="d-flex flex-wrap align-items-center gap-3">
<button type="button" id="add-relay" class="btn btn-outline-secondary">Add Relay</button>
<button name="command" type="submit" value="save" class="btn btn-primary">Submit</button>
<button name="command" type="button" class="btn btn-primary" style="display: none" id="import">Import wth Nostr extension</button>
@if (!string.IsNullOrEmpty(Model.Name))
{
<button name="command" type="submit" value="remove" class="btn btn-danger">Clear</button>
}
</div>
</form>
</div>
</div>
</div>
</form>
<template id="row">
<tr data-index="-1">
<td>

View File

@@ -26,14 +26,6 @@
}
else
{
@if (NoPayoutProcessors)
{
<div class="alert alert-warning mb-5" role="alert">
An automated payout processor is required in order to automate prism payouts.
<a class="alert-link p-0" href="@PayoutProcessorLink">Configure now</a>
</div>
}
<datalist id="users">
<option value="*">Catch-all lightning payments made against invoices in your store (excluding when other prisms are configured that capture those payments.)</option>
<option value="*@BitcoinPaymentType.Instance.ToStringNormalized()">Catch-all on-chain payments made against invoices in your store</option>
@@ -51,20 +43,61 @@ else
}
</datalist>
<h2 class="mb-4">
Prism
<a href="https://dergigi.com/2023/03/12/lightning-prisms/" class="ms-1" target="_blank" rel="noreferrer noopener">
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
</a>
</h2>
<p class="text-muted">
The prism plugin allows automated value splits for your lightning and onchain payments. You can set up multiple prisms, each with their own source (which is a <a href="@LNAddressLink">lightning address username</a>, or use *, *Onchain or *All as catch-all for all payments made against invoices, excluding ones which Prism can handle explicitly) and destinations (which are other lightning addresses,, lnurls, bitcoin addresses, an xpub, or a custom formaty provided by other plugins). The plugin will automatically credit the configured percentage of the payment to the destination (while also making sure there is 2% reserved to cater for fees, don't worry, once the lightning node tells us the exact fee amount, we credit/debit the balance after the payment), and once the configured threshold is reached, a <a href="@PayoutsLink">payout</a> will be created. Then, a <a href="@PayoutProcessorLink">payout processor</a> will run at intervals and process the payout.
</p>
<EditForm EditContext="EditContext" OnValidSubmit="Save">
<div class="sticky-header-setup"></div>
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
<h2 class="mb-0">
Prism
<a href="https://dergigi.com/2023/03/12/lightning-prisms/" class="ms-1" target="_blank" rel="noreferrer noopener">
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
</a>
</h2>
<div class="d-flex gap-3 mt-3 mt-sm-0">
@if (SelectedDestinationId is null or "null")
{
<button type="button" class="btn btn-primary mx-2" id="add-prism" @onclick="CreateNewPrism">Add Prism</button>
<button type="submit" class="btn btn-primary mx-2">Save</button>
<select class="form-select mx-2" style="max-width: fit-content" @bind="SelectedDestinationId" disabled="@(SelectedDestinationId is not null && SelectedDestinationId != "null")">
<option value="null">Select destination to configure</option>
@foreach (var destination in Destinations)
{
<option value="@destination">@destination</option>
}
<option value="">Create new destination</option>
</select>
}
@if (PrismEditButtonsFilter is not null)
{
@((MarkupString) PrismEditButtonsFilter)
}
</div>
</div>
<p class="text-muted">
The prism plugin allows automated value splits for your lightning and onchain payments. You can set up multiple prisms, each with their own source (which is a <a href="@LNAddressLink">lightning address username</a>, or use *, *Onchain or *All as catch-all for all payments made against invoices, excluding ones which Prism can handle explicitly) and destinations (which are other lightning addresses,, lnurls, bitcoin addresses, an xpub, or a custom formaty provided by other plugins). The plugin will automatically credit the configured percentage of the payment to the destination (while also making sure there is 2% reserved to cater for fees, don't worry, once the lightning node tells us the exact fee amount, we credit/debit the balance after the payment), and once the configured threshold is reached, a <a href="@PayoutsLink">payout</a> will be created. Then, a <a href="@PayoutProcessorLink">payout processor</a> will run at intervals and process the payout.
</p>
@if (NoPayoutProcessors)
{
<div class="alert alert-warning mb-5" role="alert">
An automated payout processor is required in order to automate prism payouts.
<a class="alert-link p-0" href="@PayoutProcessorLink">Configure now</a>
</div>
}
@if (StatusMessageModel != null)
{
<div class="alert alert-@StatusMessageModel.ToString(StatusMessageModel.Severity)">
@StatusMessageModel.Message
</div>
}
<div class="row" id="prism-holder">
<div class="prism col-sm-12 border border-light p-2">
@@ -125,7 +158,7 @@ else
Id="@SelectedDestinationId"
Settings="@SelectedDestination"
OnUpdate="OnDestinationUpdated"
OnCancel="o => SelectedDestinationId = null">
OnCancel="() => SelectedDestinationId = null">
</PrismDestinationEditor>
}
}
@@ -139,35 +172,6 @@ else
</PrismBalances>
@if (StatusMessageModel != null)
{
<div class="alert alert-@StatusMessageModel.ToString(StatusMessageModel.Severity)">
@StatusMessageModel.Message
</div>
}
<div class="row pt-2">
<div class="d-flex">
@if (SelectedDestinationId is null or "null")
{
<button type="button" class="btn btn-primary mx-2" id="add-prism" @onclick="CreateNewPrism">Add Prism</button>
<button type="submit" class="btn btn-primary mx-2">Save</button>
<select class="form-select mx-2" style="max-width: fit-content" @bind="SelectedDestinationId" disabled="@(SelectedDestinationId is not null && SelectedDestinationId != "null")">
<option value="null">Select destination to configure</option>
@foreach (var destination in Destinations)
{
<option value="@destination">@destination</option>
}
<option value="">Create new destination</option>
</select>
}
@if (PrismEditButtonsFilter is not null)
{
@((MarkupString) PrismEditButtonsFilter)
}
</div>
</div>
</EditForm>
}
@@ -237,13 +241,14 @@ else
EditContext.OnValidationRequested += Validate;
EditContext.OnFieldChanged += FieldChanged;
SatBreaker.PrismUpdated += SatBreakerOnPrismUpdated;
//set NoPayoutProcessors to true if there are no configured payout processores for pmi and pmichain
//set NoPayoutProcessors to true if there are no configured payout processores for pmi and pmichain
NoPayoutProcessors = PayoutProcessorFactories.Any(factory => factory.GetSupportedPaymentMethods().Contains(pmi)) && (await fetchProcessors).All(data =>
!new[] {pmi, pmichain}.Contains(data.GetPaymentMethodId()));
Loading = false;
await InvokeAsync(StateHasChanged);
}
await base.OnAfterRenderAsync(firstRender);
}
@@ -261,6 +266,7 @@ else
Settings.PendingPayouts = e.Settings.PendingPayouts;
Settings.Version = e.Settings.Version;
}
InvokeAsync(StateHasChanged);
}
@@ -279,6 +285,7 @@ else
{
MessageStore.Add(() => prism.Source, "Sources must be unique");
}
if (!(prism.Destinations?.Count > 0))
{
MessageStore.Add(() => prism.Destinations, "At least one destination is required");
@@ -299,12 +306,14 @@ else
MessageStore.Add(() => destination.Destination, "Destination is required");
continue;
}
if (!ValidateDestination(dest, true))
{
MessageStore.Add(() => destination.Destination, "Destination is not valid");
}
}
}
if (previousState != EditContext.GetValidationMessages().Any())
EditContext.NotifyValidationStateChanged();
}
@@ -315,8 +324,9 @@ else
{
return true;
}
var result = PluginHookService.ApplyFilter("prism-destination-validate", dest).Result;
return result is true or PrismDestinationValidationResult {Success: true };
return result is true or PrismDestinationValidationResult {Success: true};
}
public ValidationMessageStore MessageStore { get; set; }
@@ -331,8 +341,7 @@ else
public string LNAddressLink { get; set; }
public string PayoutsLink { get; set; }
[Parameter]
public string StoreId { get; set; }
[Parameter] public string StoreId { get; set; }
private async Task CreateNewPrism()
{
@@ -396,6 +405,7 @@ else
EditContext.OnValidationRequested -= Validate;
EditContext.OnFieldChanged -= FieldChanged;
}
SatBreaker.PrismUpdated -= SatBreakerOnPrismUpdated;
}
@@ -408,10 +418,12 @@ else
{
return true;
}
if (Destinations.Contains(arg))
{
return false;
}
return true;
}
@@ -428,6 +440,7 @@ else
{
Settings.DestinationBalance.AddOrReplace(obj.destination, obj.newBalance);
}
await SatBreaker.UpdatePrismSettingsForStore(StoreId, Settings, true);
SatBreaker.TriggerPayoutCheck();
}
@@ -457,6 +470,7 @@ else
{
SelectedDestinationId = obj.Id;
}
Settings.Destinations.AddOrReplace(SelectedDestinationId, obj.Destination);
await SaveDestinations();
var needSave = false;
@@ -466,22 +480,25 @@ else
{
await SatBreaker.WaitAndLock();
// find all prisms splits that use this id + all destination balances that use this id + all pending payouts that use this id and rename them
// find all prisms splits that use this id + all destination balances that use this id + all pending payouts that use this id and rename them
foreach (var destination in Settings.Splits.SelectMany(split => split.Destinations.Where(destination => destination.Destination == SelectedDestinationId)))
{
destination.Destination = obj.Id;
needSave = true;
}
if (Settings.DestinationBalance.Remove(SelectedDestinationId, out var db))
{
needSave = true;
Settings.DestinationBalance.Add(obj.Id, db);
}
if (Settings.Destinations.Remove(SelectedDestinationId, out var dest))
{
needSave = true;
Settings.Destinations.Add(obj.Id, dest);
}
if (needSave)
{
await SatBreaker.UpdatePrismSettingsForStore(StoreId, Settings, true);
@@ -492,11 +509,12 @@ else
SatBreaker.Unlock();
}
}
SelectedDestinationId = "null";
}
}
private async Task CancelPayout((string payoutId,TaskCompletionSource tcs) payout)
private async Task CancelPayout((string payoutId, TaskCompletionSource tcs) payout)
{
try
{
@@ -505,16 +523,14 @@ else
StatusMessageModel = new StatusMessageModel()
{
Severity = result == MarkPayoutRequest.PayoutPaidResult.Ok ?
StatusMessageModel.StatusSeverity.Success :
StatusMessageModel.StatusSeverity.Error,
Severity = result == MarkPayoutRequest.PayoutPaidResult.Ok ? StatusMessageModel.StatusSeverity.Success : StatusMessageModel.StatusSeverity.Error,
Message = result switch
{
MarkPayoutRequest.PayoutPaidResult.Ok => "Payout cancelled (please note that if the threshold is still within reach, a new payout will be created in its place)",
MarkPayoutRequest.PayoutPaidResult.NotFound => "Payout not found",
MarkPayoutRequest.PayoutPaidResult.InvalidState => "Payout state was in a non-cancellable state.",
_ => "Unknown error"
}
}
};
if (result == MarkPayoutRequest.PayoutPaidResult.Ok)
{

View File

@@ -16,17 +16,26 @@
var allowedCoins = coins.OrderBy(coin => coin.ToString()).Select(c => new SelectListItem(c.ToString(), $"{c.CryptoCode}_{c.Network}"));
}
<partial name="_StatusMessage" />
<h2 class="mb-4">@ViewData["Title"]</h2>
<form method="post">
<div class="alert alert-warning mb-4" role="alert">
If you are enabling SideShift support, we advise that you configure the invoice expiration to a minimum of 30 minutes as it may take longer than the default 15 minutes to convert the funds.
</div>
<div class="sticky-header-setup"></div>
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
<h2 class="mb-0">@ViewData["Title"]</h2>
<div class="d-flex gap-3 mt-3 mt-sm-0">
<div class="row">
<div class="col-md-10">
<form method="post">
<button name="command" type="submit" value="save" class="btn btn-primary">Save</button>
</div>
</div>
<partial name="_StatusMessage"/>
<div class="alert alert-warning mb-4" role="alert">
If you are enabling SideShift support, we advise that you configure the invoice expiration to a minimum of 30 minutes as it may take longer than the default 15 minutes to convert the funds.
</div>
<div class="row">
<div class="col-xl-8 col-xxl-constrain">
<div class="form-group">
<div class="d-flex align-items-center">
<input asp-for="Enabled" type="checkbox" class="btcpay-toggle me-2"/>
@@ -34,21 +43,22 @@
</div>
</div>
<div class="form-group">
<label asp-for="PreferredTargetPaymentMethodId" class="form-label" data-required>Convert always to this payment method, if possible</label>
<select asp-for="PreferredTargetPaymentMethodId" asp-items="allowedPaymentMethods" class="form-select"></select>
</div>
<div class="form-group">
<label asp-for="ExplicitMethods" class="form-label" data-required>Show these conversion options as individual payment methods</label>
<select style="min-height: 300px;" multiple asp-for="ExplicitMethods" asp-items="@allowedCoins" class="form-select"></select>
</div>
<div class="form-group">
<div class="d-flex align-items-center">
<input asp-for="OnlyShowExplicitMethods" type="checkbox" class="btcpay-toggle me-2"/>
<label asp-for="OnlyShowExplicitMethods" class="form-label mb-0 me-1">Only show explicit methods</label>
</div>
</div>
<label asp-for="PreferredTargetPaymentMethodId" class="form-label" data-required>Convert always to this payment method, if possible</label>
<select asp-for="PreferredTargetPaymentMethodId" asp-items="allowedPaymentMethods" class="form-select"></select>
</div>
<div class="form-group">
<label asp-for="ExplicitMethods" class="form-label" data-required>Show these conversion options as individual payment methods</label>
<select style="min-height: 300px;" multiple asp-for="ExplicitMethods" asp-items="@allowedCoins" class="form-select"></select>
</div>
<div class="form-group">
<div class="d-flex align-items-center">
<input asp-for="OnlyShowExplicitMethods" type="checkbox" class="btcpay-toggle me-2"/>
<label asp-for="OnlyShowExplicitMethods" class="form-label mb-0 me-1">Only show explicit methods</label>
</div>
</div>
<button name="command" type="submit" value="save" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
</form>

View File

@@ -1,31 +1,43 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Client
@using BTCPayServer.Plugins.TicketTailor
@using BTCPayServer.Plugins.TicketTailor
@using Microsoft.AspNetCore.Mvc.TagHelpers
@using Microsoft.AspNetCore.Routing
@using BTCPayServer.Abstractions.Contracts
@model BTCPayServer.Plugins.TicketTailor.UpdateTicketTailorSettingsViewModel
@inject IScopeProvider ScopeProvider
@{
var storeId = ScopeProvider.GetCurrentStoreId();
Layout = "../Shared/_NavLayout.cshtml";
ViewData["NavPartialName"] = "../UIStores/_Nav";
ViewData.SetActivePage("TicketTailor", "Update Store TicketTailor Settings", null);
Model.SpecificTickets ??= new List<SpecificTicket>();
}
<h2 class="mt-1 mb-4">@ViewData["Title"]</h2>
@if (ViewContext.ModelState.IsValid && Model.EventId is not null)
{
<div class="alert alert-warning">
Please ensure that emails in your store are configured if you wish to send the tickets via email to customers as TicketTailor does not handle it for tickets issued via its API.
<form method="post">
<div class="sticky-header-setup"></div>
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
<h2 class="mb-0">@ViewData["Title"]</h2>
<div class="d-flex gap-3 mt-3 mt-sm-0">
<input type="submit" value="Save" name="command" class="btn btn-primary"/>
@if (this.ViewContext.ModelState.IsValid && Model.EventId is not null)
{
<a class="btn btn-secondary" href=" @Url.Action("View", "TicketTailor", new {storeId})">
Ticket purchase page
</a>
}
</div>
</div>
}
<div class="row">
<div class="col-xl-8 col-xxl-constrain">
<form method="post">
<partial name="_StatusMessage"/>
@if (ViewContext.ModelState.IsValid && Model.EventId is not null)
{
<div class="alert alert-warning">
Please ensure that emails in your store are configured if you wish to send the tickets via email to customers as TicketTailor does not handle it for tickets issued via its API.
</div>
}
<div class="row">
<div class="col-xl-8 col-xxl-constrain">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
@@ -97,6 +109,7 @@
{
continue;
}
<div class="card">
<div class="card-header h5">
@ticketType.Name
@@ -120,24 +133,15 @@
</div>
</div>
<div class="card-footer">
<button type="submit" value="remove-specific-ticket:@index" name="command" class="btn btn-outline-danger">Remove</button>
<button type="submit" value="remove-specific-ticket:@index" name="command" class="btn btn-outline-danger">Remove</button>
</div>
</div>
}
</div>
}
}
<div class="form-group mt-4">
<input type="submit" value="Save" name="command" class="btn btn-primary"/>
@if (this.ViewContext.ModelState.IsValid && Model.EventId is not null)
{
<a class="btn btn-secondary" href=" @Url.Action("View", "TicketTailor", new {storeId})">
Ticket purchase page
</a>
}
</div>
</form>
</div>
</div>
</div>
<partial name="_ValidationScriptsPartial"/>
</form>
<partial name="_ValidationScriptsPartial"/>