Wallet: Delete custom labels (#5324)

* Tom Select improvements

* Wallet: Delete custom labels

Closes #5237.
This commit is contained in:
d11n
2023-09-19 02:55:04 +02:00
committed by GitHub
parent 44df8cf0c5
commit 77d8e202d3
11 changed files with 148 additions and 13 deletions

View File

@@ -385,7 +385,8 @@ retry:
EqualJsContent(expected, actual);
actual = GetFileContent("BTCPayServer", "wwwroot", "vendor", "tom-select", "tom-select.complete.min.js").Trim();
expected = (await (await client.GetAsync($"https://cdn.jsdelivr.net/npm/tom-select@2.2.2/dist/js/tom-select.complete.min.js")).Content.ReadAsStringAsync()).Trim();
version = Regex.Match(actual, "Tom Select v([0-9]+.[0-9]+.[0-9]+)").Groups[1].Value;
expected = (await (await client.GetAsync($"https://cdn.jsdelivr.net/npm/tom-select@{version}/dist/js/tom-select.complete.min.js")).Content.ReadAsStringAsync()).Trim();
EqualJsContent(expected, actual);
actual = GetFileContent("BTCPayServer", "wwwroot", "vendor", "dom-confetti", "dom-confetti.min.js").Trim();

View File

@@ -3,7 +3,7 @@
@model BTCPayServer.Components.LabelManager.LabelViewModel
@{
var elementId = "a" + Encoders.Base58.EncodeData(RandomUtils.GetBytes(16));
var fetchUrl = Url.Action("GetLabels", "UIWallets", new {
var fetchUrl = Url.Action("LabelsJson", "UIWallets", new {
walletId = Model.WalletObjectId.WalletId,
excludeTypes = Safe.Json(Model.ExcludeTypes)
});

View File

@@ -1381,9 +1381,9 @@ namespace BTCPayServer.Controllers
return Ok();
}
[HttpGet("{walletId}/labels")]
[HttpGet("{walletId}/labels.json")]
[IgnoreAntiforgeryToken]
public async Task<IActionResult> GetLabels(
public async Task<IActionResult> LabelsJson(
[ModelBinder(typeof(WalletIdModelBinder))] WalletId walletId,
bool excludeTypes,
string? type = null,
@@ -1397,14 +1397,62 @@ namespace BTCPayServer.Controllers
: await WalletRepository.GetWalletLabels(walletObjectId);
return Ok(labels
.Where(l => !excludeTypes || !WalletObjectData.Types.AllTypes.Contains(l.Label))
.Select(tuple => new
.Select(tuple => new WalletLabelModel
{
label = tuple.Label,
color = tuple.Color,
textColor = ColorPalette.Default.TextColor(tuple.Color)
Label = tuple.Label,
Color = tuple.Color,
TextColor = ColorPalette.Default.TextColor(tuple.Color)
}));
}
[HttpGet("{walletId}/labels")]
public async Task<IActionResult> WalletLabels(
[ModelBinder(typeof(WalletIdModelBinder))]
WalletId walletId)
{
if (walletId.StoreId == null)
return NotFound();
var labels = await WalletRepository.GetWalletLabels(walletId);
var vm = new WalletLabelsModel
{
WalletId = walletId,
Labels = labels
.Where(l => !WalletObjectData.Types.AllTypes.Contains(l.Label))
.Select(tuple => new WalletLabelModel
{
Label = tuple.Label,
Color = tuple.Color,
TextColor = ColorPalette.Default.TextColor(tuple.Color)
})
};
return View(vm);
}
[HttpPost("{walletId}/labels/{id}/remove")]
public async Task<IActionResult> RemoveWalletLabel(
[ModelBinder(typeof(WalletIdModelBinder))]
WalletId walletId, string id)
{
if (walletId.StoreId == null)
return NotFound();
var labels = new[] { id };
;
if (await WalletRepository.RemoveWalletLabels(walletId, labels))
{
TempData[WellKnownTempData.SuccessMessage] = "The label has been successfully removed.";
}
else
{
TempData[WellKnownTempData.ErrorMessage] = "The label could not be removed.";
}
return RedirectToAction(nameof(WalletLabels), new { walletId });
}
private string GetImage(PaymentMethodId paymentMethodId, BTCPayNetwork network)
{
var res = paymentMethodId.PaymentType == PaymentTypes.BTCLike

View File

@@ -0,0 +1,16 @@
using System.Collections.Generic;
namespace BTCPayServer.Models.WalletViewModels;
public class WalletLabelsModel
{
public WalletId WalletId { get; set; }
public IEnumerable<WalletLabelModel> Labels { get; set; }
}
public class WalletLabelModel
{
public string Label { get; set; }
public string Color { get; set; }
public string TextColor { get; set; }
}

View File

@@ -564,6 +564,18 @@ namespace BTCPayServer.Services
}
}
public async Task<bool> RemoveWalletLabels(WalletId id, params string[] labels)
{
ArgumentNullException.ThrowIfNull(id);
var count = 0;
foreach (var l in labels.Select(l => l.Trim()))
{
var labelObjId = new WalletObjectId(id, WalletObjectData.Types.Label, l);
count += await RemoveWalletObjects(labelObjId) ? 1 : 0;
}
return count > 0;
}
public async Task SetWalletObject(WalletObjectId id, JObject? data)
{
ArgumentNullException.ThrowIfNull(id);

View File

@@ -16,7 +16,6 @@
<script src="~/vendor/vue-qrcode/vue-qrcode.min.js" asp-append-version="true"></script>
<script src="~/vendor/ur-registry/urlib.min.js" asp-append-version="true"></script>
<script src="~/vendor/vue-qrcode-reader/VueQrcodeReader.umd.min.js" asp-append-version="true"></script>
<link href="~/vendor/vue-qrcode-reader/vue-qrcode-reader.css" rel="stylesheet" asp-append-version="true"/>
}
@@ -200,6 +199,11 @@
</div>
<button type="submit" class="btn btn-primary mt-2" id="SavePaymentSettings">Save Payment Settings</button>
</form>
<h3 class="mt-5">Labels</h3>
<p>
<a asp-controller="UIWallets" asp-action="WalletLabels" asp-route-walletId="@Model.WalletId">Manage labels</a>
</p>
</div>
</div>
</div>

View File

@@ -0,0 +1,52 @@
@using BTCPayServer.Abstractions.Models
@model WalletLabelsModel
@{
var walletId = Context.GetRouteValue("walletId").ToString();
Layout = "../Shared/_NavLayout.cshtml";
ViewData.SetActivePage(WalletsNavPages.Settings, "Wallet Labels", walletId);
}
@section PageFootContent {
<script>
delegate('click', '.btn-delete', event => { event.preventDefault() })
</script>
}
<h3>@ViewData["Title"]</h3>
@if (Model.Labels.Any())
{
<table class="table table-hover table-responsive-md">
<thead>
<tr>
<th>Label</th>
<th class="text-end">Actions</th>
</tr>
</thead>
<tbody>
@foreach (var label in Model.Labels)
{
<tr>
<td>
<div class="transaction-label" style="--label-bg:@label.Color;--label-fg:@label.TextColor">
<span>@label.Label</span>
</div>
</td>
<td class="text-end">
<form method="post" asp-action="RemoveWalletLabel" asp-route-walletId="@Model.WalletId" asp-route-id="@label.Label">
<button class="btn btn-link btn-delete p-0" type="submit" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The label <strong>@Html.Encode(label.Label)</strong> will be removed from this wallet and its associated transactions." data-confirm-input="DELETE">Remove</button>
</form>
</td>
</tr>
}
</tbody>
</table>
<partial name="_Confirm" model="@(new ConfirmModel("Remove label", "This label will be removed from this wallet and its associated transactions.", "Remove"))" />
}
else
{
<p class="text-secondary mt-3">
There are no custom labels yet. You can create custom labels by assigning them to your <a asp-action="WalletTransactions" asp-route-walletId="@walletId">transactions</a>.
</p>
}

View File

@@ -33,7 +33,7 @@ async function initLabelManager (elementId) {
: '--label-bg:var(--btcpay-neutral-300);--label-fg:var(--btcpay-neutral-800)'
if (element) {
const { fetchUrl, updateUrl, walletId, walletObjectType, walletObjectId, labels,selectElement } = element.dataset;
const { fetchUrl, updateUrl, walletId, walletObjectType, walletObjectId, labels, selectElement } = element.dataset;
const commonCallId = `walletLabels-${walletId}`;
if (!window[commonCallId]) {
window[commonCallId] = fetch(fetchUrl, {
@@ -44,7 +44,6 @@ async function initLabelManager (elementId) {
},
}).then(res => res.json());
}
const selectElementI = document.getElementById(selectElement);
const items = element.value.split(',').filter(x => !!x);
const options = await window[commonCallId].then(labels => {
const newItems = items.filter(item => !labels.find(label => label.label === item));
@@ -92,7 +91,8 @@ async function initLabelManager (elementId) {
}));
},
async onChange (values) {
if(selectElementI){
const selectElementI = selectElement ? document.getElementById(selectElement) : null;
if (selectElementI){
while (selectElementI.options.length > 0) {
selectElementI.remove(0);
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long