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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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

@ -563,6 +563,18 @@ namespace BTCPayServer.Services
await RemoveWalletObjectLink(labelObjId, id);
}
}
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)
{

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

File diff suppressed because one or more lines are too long