Unify delete confirmation confirm dialog (#6965)
What changed, and why it matters
This commit standardizes the wording and behavior of delete-confirmation dialogs across the BTCPay Server web interface. Previously, different screens asked users to type different words such as "DELETE" or "REMOVE" to confirm deletion. Now every confirmation prompt uses the same word, "Delete," and the check is case-insensitive. This is a user-experience and consistency improvement, not a fix for a security vulnerability.
No security action required. Treat as a routine UI/UX consistency refactor. If reviewing, verify that the server-side POST handlers still enforce the expected permissions and anti-forgery tokens, which this commit does not modify.
Security signals we found
No change to authentication or authorization checks
No change to request routing or controller action semantics
No change to anti-forgery token handling
Confirmation prompt remains a client-side UX safeguard only; the actual delete still requires a POST to the protected endpoint
Case-insensitive comparison could marginally reduce friction but does not weaken server-side enforcement
Evidence from the diff
The change unifies the shared _Confirm.cshtml partial and all call sites so that the confirmation input value is normalized to the localized string “Delete” and compared case-insensitively. The JavaScript now upper-cases the displayed prompt text but lower-cases both the user input and expected value before comparison. Several controllers and Razor views were updated to pass StringLocalizer["Delete"] (or the appropriate action label) instead of hard-coded English strings. Test helpers were refactored to match the new unified behavior. No access-control, authorization, or data-handling logic was changed.
Changed components
BTCPayServer/Views/Shared/_Confirm.cshtmlBTCPayServer/Controllers/UILNURLAuthController.csBTCPayServer/Controllers/UIServerController.Users.csBTCPayServer/Controllers/UIServerController.csBTCPayServer/Controllers/UIStorePullPaymentsController.PullPayments.csBTCPayServer/Controllers/UIStoresController.Onchain.csBTCPayServer/Controllers/UIUserStoresController.csBTCPayServer/Fido2/UIFido2Controller.csVarious Razor views using the ConfirmModal/_Confirm partialBTCPayServer.Tests/PlaywrightTester.csBTCPayServer.Tests/PlaywrightTests.csInspect captured patch +72 / −73
diff --git a/BTCPayServer.Tests/PlaywrightTester.cs b/BTCPayServer.Tests/PlaywrightTester.cs
index b84f344..3335a0c 100644
--- a/BTCPayServer.Tests/PlaywrightTester.cs
+++ b/BTCPayServer.Tests/PlaywrightTester.cs
@@ -762,5 +762,11 @@ namespace BTCPayServer.Tests
});
return await new StreamReader(await download.CreateReadStreamAsync()).ReadToEndAsync();
}
+
+ public async Task ConfirmDeleteModal()
+ {
+ await Page.FillAsync("#ConfirmInput", "DELETE");
+ await Page.ClickAsync("#ConfirmContinue");
+ }
}
}
diff --git a/BTCPayServer.Tests/PlaywrightTests.cs b/BTCPayServer.Tests/PlaywrightTests.cs
index 53ce837..8938d30 100644
--- a/BTCPayServer.Tests/PlaywrightTests.cs
+++ b/BTCPayServer.Tests/PlaywrightTests.cs
@@ -144,8 +144,7 @@ namespace BTCPayServer.Tests
await s.GoToStore(StoreNavPages.Forms);
Assert.Contains("Custom Form 1", await s.Page.ContentAsync());
await s.Page.GetByRole(AriaRole.Link, new() { Name = "Remove" }).ClickAsync();
- await s.Page.FillAsync("#ConfirmInput", "DELETE");
- await s.Page.ClickAsync("#ConfirmContinue");
+ await s.ConfirmDeleteModal();
Assert.DoesNotContain("Custom Form 1", await s.Page.ContentAsync());
await s.ClickPagePrimary();
await s.Page.FillAsync("[name='Name']", "Custom Form 2");
@@ -491,8 +490,7 @@ namespace BTCPayServer.Tests
//let's test delete user quickly while we're at it
await s.GoToProfile();
await s.Page.ClickAsync("#delete-user");
- await s.Page.FillAsync("#ConfirmInput", "DELETE");
- await s.Page.ClickAsync("#ConfirmContinue");
+ await s.ConfirmDeleteModal();
Assert.Contains("/login", s.Page.Url);
}
@@ -1488,16 +1486,14 @@ namespace BTCPayServer.Tests
Assert.Equal(2, await deleteLinks.CountAsync());
await deleteLinks.First.ClickAsync();
- await s.Page.FillAsync("#ConfirmInput", "REMOVE");
- await s.Page.ClickAsync("#ConfirmContinue");
+ await s.ConfirmDeleteModal();
await s.FindAlertMessage();
deleteLinks = s.Page.GetByRole(AriaRole.Link, new() { Name = "Remove" });
Assert.Equal(1, await deleteLinks.CountAsync());
await deleteLinks.First.ClickAsync();
- await s.Page.FillAsync("#ConfirmInput", "REMOVE");
- await s.Page.ClickAsync("#ConfirmContinue");
+ await s.ConfirmDeleteModal();
await s.FindAlertMessage();
Assert.Contains("There are no rules yet.", await s.Page.ContentAsync());
@@ -1712,8 +1708,7 @@ namespace BTCPayServer.Tests
Assert.Contains(await passEl.TextContentAsync(), "hellorockstar", StringComparison.OrdinalIgnoreCase);
await s.Page.ClickAsync("#delete");
await s.Page.WaitForSelectorAsync("#ConfirmInput");
- await s.Page.FillAsync("#ConfirmInput", "DELETE");
- await s.Page.ClickAsync("#ConfirmContinue");
+ await s.ConfirmDeleteModal();
await s.FindAlertMessage();
seedEl = s.Page.Locator("#Seed");
Assert.Contains("Seed removed", await seedEl.TextContentAsync(), StringComparison.OrdinalIgnoreCase);
@@ -2131,8 +2126,7 @@ namespace BTCPayServer.Tests
var deleteLinks = await s.Page.Locator("a:has-text('Delete')").AllAsync();
Assert.Equal(2, deleteLinks.Count);
await deleteLinks[0].ClickAsync();
- await s.Page.FillAsync("#ConfirmInput", "DELETE");
- await s.Page.ClickAsync("#ConfirmContinue");
+ await s.ConfirmDeleteModal();
deleteLinks = await s.Page.Locator("a:has-text('Delete')").AllAsync();
Assert.Single(deleteLinks);
await s.FindAlertMessage();
@@ -2213,8 +2207,7 @@ namespace BTCPayServer.Tests
TestLogs.LogInformation("Let's see if we can delete store with some webhooks inside");
await s.GoToStore();
await s.Page.ClickAsync("#DeleteStore");
- await s.Page.FillAsync("#ConfirmInput", "DELETE");
- await s.Page.ClickAsync("#ConfirmContinue");
+ await s.ConfirmDeleteModal();
await s.FindAlertMessage();
}
diff --git a/BTCPayServer/Controllers/UILNURLAuthController.cs b/BTCPayServer/Controllers/UILNURLAuthController.cs
index 3bbb7aa..bed3f1d 100644
--- a/BTCPayServer/Controllers/UILNURLAuthController.cs
+++ b/BTCPayServer/Controllers/UILNURLAuthController.cs
@@ -41,7 +41,7 @@ namespace BTCPayServer
return View("Confirm",
new ConfirmModel(StringLocalizer["Remove LNURL Auth link"],
StringLocalizer["Your account will no longer have this Lightning wallet as an option for two-factor authentication."],
- StringLocalizer["Remove"]));
+ StringLocalizer["Delete"]));
}
[HttpPost("{id}/delete")]
diff --git a/BTCPayServer/Controllers/UIServerController.Users.cs b/BTCPayServer/Controllers/UIServerController.Users.cs
index c30289f..a196ab1 100644
--- a/BTCPayServer/Controllers/UIServerController.Users.cs
+++ b/BTCPayServer/Controllers/UIServerController.Users.cs
@@ -309,7 +309,7 @@ namespace BTCPayServer.Controllers
StringLocalizer["Delete"]));
}
- return View("Confirm", new ConfirmModel(StringLocalizer["Delete user"], $"The user <strong>{Html.Encode(user.Email)}</strong> will be permanently deleted. Are you sure?", "Delete"));
+ return View("Confirm", new ConfirmModel(StringLocalizer["Delete user"], $"The user <strong>{Html.Encode(user.Email)}</strong> will be permanently deleted. Are you sure?", StringLocalizer["Delete"]));
}
[HttpPost("server/users/{userId}/delete")]
@@ -337,7 +337,7 @@ namespace BTCPayServer.Controllers
return View("Confirm", new ConfirmModel(StringLocalizer["Disable admin"],
$"Unable to proceed: As the user <strong>{Html.Encode(user.Email)}</strong> is the last enabled admin, it cannot be disabled."));
}
- return View("Confirm", new ConfirmModel($"{(enable ? "Enable" : "Disable")} user", $"The user <strong>{Html.Encode(user.Email)}</strong> will be {(enable ? "enabled" : "disabled")}. Are you sure?", (enable ? "Enable" : "Disable")));
+ return View("Confirm", new ConfirmModel($"{(enable ? "Enable" : "Disable")} user", $"The user <strong>{Html.Encode(user.Email)}</strong> will be {(enable ? "enabled" : "disabled")}. Are you sure?", (enable ? StringLocalizer["Enable"] : StringLocalizer["Disable"])));
}
[HttpPost("server/users/{userId}/toggle")]
@@ -366,7 +366,7 @@ namespace BTCPayServer.Controllers
if (user == null)
return NotFound();
- return View("Confirm", new ConfirmModel($"{(approved ? "Approve" : "Unapprove")} user", $"The user <strong>{Html.Encode(user.Email)}</strong> will be {(approved ? "approved" : "unapproved")}. Are you sure?", (approved ? "Approve" : "Unapprove")));
+ return View("Confirm", new ConfirmModel($"{(approved ? StringLocalizer["Approve"] : StringLocalizer["Unapprove"])} user", $"The user <strong>{Html.Encode(user.Email)}</strong> will be {(approved ? "approved" : "unapproved")}. Are you sure?", (approved ? StringLocalizer["Approve"] : StringLocalizer["Unapprove"])));
}
[HttpPost("server/users/{userId}/approve")]
@@ -392,7 +392,7 @@ namespace BTCPayServer.Controllers
if (user == null)
return NotFound();
- return View("Confirm", new ConfirmModel(StringLocalizer["Send verification email"], $"This will send a verification email to <strong>{Html.Encode(user.Email)}</strong>.", "Send"));
+ return View("Confirm", new ConfirmModel(StringLocalizer["Send verification email"], $"This will send a verification email to <strong>{Html.Encode(user.Email)}</strong>.", StringLocalizer["Send"]));
}
[HttpPost("server/users/{userId}/verification-email")]
diff --git a/BTCPayServer/Controllers/UIServerController.cs b/BTCPayServer/Controllers/UIServerController.cs
index a0562b9..d922379 100644
--- a/BTCPayServer/Controllers/UIServerController.cs
+++ b/BTCPayServer/Controllers/UIServerController.cs
@@ -919,7 +919,7 @@ namespace BTCPayServer.Controllers
return NotFound();
return View("Confirm",
new ConfirmModel("Delete dynamic DNS service",
- $"Deleting the dynamic DNS service for <strong>{Html.Encode(hostname)}</strong> means your BTCPay Server will stop updating the associated DNS record periodically.", "Delete"));
+ $"Deleting the dynamic DNS service for <strong>{Html.Encode(hostname)}</strong> means your BTCPay Server will stop updating the associated DNS record periodically.", StringLocalizer["Delete"]));
}
[HttpPost("server/services/dynamic-dns/{hostname}/delete")]
@@ -1054,7 +1054,7 @@ namespace BTCPayServer.Controllers
[HttpGet("server/services/ssh/disable")]
public IActionResult SSHServiceDisable()
{
- return View("Confirm", new ConfirmModel("Disable modification of SSH settings", "This action is permanent and will remove the ability to change the SSH settings via the BTCPay Server user interface.", "Disable"));
+ return View("Confirm", new ConfirmModel(StringLocalizer["Disable modification of SSH settings"], StringLocalizer["This action is permanent and will remove the ability to change the SSH settings via the BTCPay Server user interface."], StringLocalizer["Disable"]));
}
[HttpPost("server/services/ssh/disable")]
diff --git a/BTCPayServer/Controllers/UIStorePullPaymentsController.PullPayments.cs b/BTCPayServer/Controllers/UIStorePullPaymentsController.PullPayments.cs
index e5f898e..7800a3f 100644
--- a/BTCPayServer/Controllers/UIStorePullPaymentsController.PullPayments.cs
+++ b/BTCPayServer/Controllers/UIStorePullPaymentsController.PullPayments.cs
@@ -76,7 +76,7 @@ namespace BTCPayServer.Controllers
_payoutProcessorService = payoutProcessorService;
_payoutProcessorFactories = payoutProcessorFactories;
}
-
+
[HttpGet("stores/{storeId}/pull-payments/new")]
[Authorize(Policy = Policies.CanCreateNonApprovedPullPayments, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
public IActionResult NewPullPayment(string storeId)
@@ -119,7 +119,7 @@ namespace BTCPayServer.Controllers
model.PayoutMethods ??= new List<string>();
if (!model.PayoutMethods.Any())
{
- // Since we assign all payment methods to be selected by default above we need to update
+ // Since we assign all payment methods to be selected by default above we need to update
// them here to reflect user's selection so that they can correct their mistake
model.PayoutMethodsItem =
paymentMethodOptions.Select(id => new SelectListItem(id.ToString(), id.ToString(), false));
@@ -263,7 +263,7 @@ namespace BTCPayServer.Controllers
string pullPaymentId)
{
return View("Confirm",
- new ConfirmModel(StringLocalizer["Archive pull payment"], StringLocalizer["Do you really want to archive the pull payment?"], "Archive"));
+ new ConfirmModel(StringLocalizer["Archive pull payment"], StringLocalizer["Do you really want to archive the pull payment?"], StringLocalizer["Archive"]));
}
[HttpPost("stores/{storeId}/pull-payments/{pullPaymentId}/archive")]
diff --git a/BTCPayServer/Controllers/UIStoresController.Onchain.cs b/BTCPayServer/Controllers/UIStoresController.Onchain.cs
index 05f95b9..de16eb2 100644
--- a/BTCPayServer/Controllers/UIStoresController.Onchain.cs
+++ b/BTCPayServer/Controllers/UIStoresController.Onchain.cs
@@ -651,7 +651,7 @@ public partial class UIStoresController
{
Title = StringLocalizer["Remove {0} wallet", network.CryptoCode],
Description = WalletRemoveWarning(derivation.IsHotWallet, network.CryptoCode),
- Action = StringLocalizer["Remove"]
+ Action = StringLocalizer["Delete"]
});
}
diff --git a/BTCPayServer/Controllers/UIUserStoresController.cs b/BTCPayServer/Controllers/UIUserStoresController.cs
index 5a796da..7c8b3dd 100644
--- a/BTCPayServer/Controllers/UIUserStoresController.cs
+++ b/BTCPayServer/Controllers/UIUserStoresController.cs
@@ -125,7 +125,7 @@ namespace BTCPayServer.Controllers
var store = HttpContext.GetStoreData();
if (store == null)
return NotFound();
- return View("Confirm", new ConfirmModel(StringLocalizer["Delete store {0}", store.StoreName], StringLocalizer["This store will still be accessible to users sharing it"], "Delete"));
+ return View("Confirm", new ConfirmModel(StringLocalizer["Delete store {0}", store.StoreName], StringLocalizer["This store will still be accessible to users sharing it"], StringLocalizer["Delete"]));
}
[HttpPost("{storeId}/me/delete")]
diff --git a/BTCPayServer/Fido2/UIFido2Controller.cs b/BTCPayServer/Fido2/UIFido2Controller.cs
index 8762080..0fe30a9 100644
--- a/BTCPayServer/Fido2/UIFido2Controller.cs
+++ b/BTCPayServer/Fido2/UIFido2Controller.cs
@@ -33,7 +33,7 @@ namespace BTCPayServer.Fido2
[HttpGet("{id}/delete")]
public IActionResult Remove(string id)
{
- return View("Confirm", new ConfirmModel(StringLocalizer["Remove security device"], StringLocalizer["Your account will no longer have this security device as an option for two-factor authentication."], StringLocalizer["Remove"]));
+ return View("Confirm", new ConfirmModel(StringLocalizer["Remove security device"], StringLocalizer["Your account will no longer have this security device as an option for two-factor authentication."], StringLocalizer["Delete"]));
}
[HttpPost("{id}/delete")]
diff --git a/BTCPayServer/Plugins/Emails/Views/UIStoreEmailRules/StoreEmailRulesList.cshtml b/BTCPayServer/Plugins/Emails/Views/UIStoreEmailRules/StoreEmailRulesList.cshtml
index f24147e..1f5ba7f 100644
--- a/BTCPayServer/Plugins/Emails/Views/UIStoreEmailRules/StoreEmailRulesList.cshtml
+++ b/BTCPayServer/Plugins/Emails/Views/UIStoreEmailRules/StoreEmailRulesList.cshtml
@@ -49,7 +49,7 @@
<td class="actions-col" permission="@Policies.CanModifyStoreSettings">
<div class="d-inline-flex align-items-center gap-3">
<a asp-action="StoreEmailRulesEdit" asp-route-storeId="@storeId" asp-route-ruleId="@rule.Data.Id">Edit</a>
- <a asp-action="StoreEmailRulesDelete" asp-route-storeId="@storeId" asp-route-ruleId="@rule.Data.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="@ViewLocalizer["This action will remove the rule with the trigger <b>{0}</b>.", Html.Encode(rule.Trigger)]" data-confirm-input="@StringLocalizer["REMOVE"]" text-translate="true">Remove</a>
+ <a asp-action="StoreEmailRulesDelete" asp-route-storeId="@storeId" asp-route-ruleId="@rule.Data.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="@ViewLocalizer["This action will remove the rule with the trigger <b>{0}</b>.", Html.Encode(rule.Trigger)]" data-confirm-input="@StringLocalizer["Delete"]" text-translate="true">Remove</a>
</div>
</td>
</tr>
diff --git a/BTCPayServer/Plugins/Webhooks/Views/Webhooks.cshtml b/BTCPayServer/Plugins/Webhooks/Views/Webhooks.cshtml
index ddbcaa1..380b4b6 100644
--- a/BTCPayServer/Plugins/Webhooks/Views/Webhooks.cshtml
+++ b/BTCPayServer/Plugins/Webhooks/Views/Webhooks.cshtml
@@ -53,7 +53,7 @@
<td class="d-block text-break">@wh.Url</td>
<td class="actions-col text-md-nowrap" permission="@Policies.CanModifyStoreSettings">
<a asp-action="ModifyWebhook" asp-route-storeId="@Context.GetRouteValue("storeId")" asp-route-webhookId="@wh.Id" text-translate="true">Modify</a> -
- <a asp-action="DeleteWebhook" asp-route-storeId="@Context.GetRouteValue("storeId")" asp-route-webhookId="@wh.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-confirm-input="DELETE" text-translate="true">Delete</a>
+ <a asp-action="DeleteWebhook" asp-route-storeId="@Context.GetRouteValue("storeId")" asp-route-webhookId="@wh.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-confirm-input="@StringLocalizer["Delete"]" text-translate="true">Delete</a>
</td>
</tr>
}
diff --git a/BTCPayServer/Views/Shared/Crowdfund/UpdateCrowdfund.cshtml b/BTCPayServer/Views/Shared/Crowdfund/UpdateCrowdfund.cshtml
index 914cd0c..333ce17 100644
--- a/BTCPayServer/Views/Shared/Crowdfund/UpdateCrowdfund.cshtml
+++ b/BTCPayServer/Views/Shared/Crowdfund/UpdateCrowdfund.cshtml
@@ -165,7 +165,7 @@
<span asp-validation-for="StartDate" class="text-danger"></span>
<span asp-validation-for="EndDate" class="text-danger"></span>
</div>
-
+
<div class="form-group mt-4" id="ResetRow" hidden="@(Model.StartDate == null)">
<div class="d-flex align-items-center mb-3">
<input asp-for="IsRecurring" type="checkbox" class="btcpay-toggle me-3" data-bs-toggle="collapse" data-bs-target="#ResetEverySettings" aria-expanded="@(Model.IsRecurring)" aria-controls="ResetEverySettings" />
@@ -175,7 +175,7 @@
<div class="text-muted" text-translate="true">Reset goal after a specific period of time, based on your crowdfund's start date.</div>
</div>
</div>
-
+
<div class="collapse @(Model.IsRecurring ? "show" : "")" id="ResetEverySettings">
<div class="form-group mb-0 pt-2 w-250px">
<label asp-for="ResetEveryAmount" class="form-label"></label>
@@ -222,14 +222,14 @@
<label asp-for="EnforceTargetAmount" class="form-check-label"></label>
<span asp-validation-for="EnforceTargetAmount" class="text-danger"></span>
</div>
-
+
<h3 class="mt-5 mb-4" text-translate="true">Crowdfund Behavior</h3>
<div class="d-flex">
<input asp-for="UseAllStoreInvoices" type="checkbox" class="btcpay-toggle me-3" />
<label asp-for="UseAllStoreInvoices" class="form-check-label"></label>
<span asp-validation-for="UseAllStoreInvoices" class="text-danger"></span>
</div>
-
+
<h3 class="mt-5 mb-4" text-translate="true">Checkout</h3>
<div class="form-group">
<label asp-for="FormId" class="form-label"></label>
@@ -384,8 +384,8 @@ Please insert valid HTML here. Only meta tags accepted.'>
}
</button>
</form>
- <a id="DeleteApp" class="btn btn-outline-danger" asp-controller="UIApps" asp-action="DeleteApp" asp-route-appId="@Model.AppId" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The app <strong>@Html.Encode(Model.AppName)</strong> and its settings will be permanently deleted." data-confirm-input="DELETE" permission="@Policies.CanModifyStoreSettings">Delete this app</a>
+ <a id="DeleteApp" class="btn btn-outline-danger" asp-controller="UIApps" asp-action="DeleteApp" asp-route-appId="@Model.AppId" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The app <strong>@Html.Encode(Model.AppName)</strong> and its settings will be permanently deleted." data-confirm-input="@StringLocalizer["Delete"]" permission="@Policies.CanModifyStoreSettings">Delete this app</a>
</div>
-<partial name="_Confirm" model="@(new ConfirmModel("Delete app", "This app will be removed from this store.", "Delete"))" permission="@Policies.CanModifyStoreSettings" />
+<partial name="_Confirm" model="@(new ConfirmModel(StringLocalizer["Delete app"], StringLocalizer["This app will be removed from this store."], StringLocalizer["Delete"]))" permission="@Policies.CanModifyStoreSettings" />
diff --git a/BTCPayServer/Views/Shared/_Confirm.cshtml b/BTCPayServer/Views/Shared/_Confirm.cshtml
index e563b98..ac97999 100644
--- a/BTCPayServer/Views/Shared/_Confirm.cshtml
+++ b/BTCPayServer/Views/Shared/_Confirm.cshtml
@@ -39,15 +39,15 @@
if (confirmInput) {
$text.removeAttribute('hidden')
$continue.setAttribute('disabled', 'disabled')
- $inputText.textContent = confirmInput
+ $inputText.textContent = confirmInput.toUpperCase()
$input.setAttribute("autocomplete", "off")
$input.addEventListener('input', event => {
- event.target.value.trim() === confirmInput
+ event.target.value.trim().toLowerCase() === confirmInput.toLowerCase()
? $continue.removeAttribute('disabled')
: $continue.setAttribute('disabled', 'disabled')
})
$form.addEventListener('submit', event => {
- if ($input.value.trim() !== confirmInput) {
+ if ($input.value.trim().toLowerCase() !== confirmInput.toLowerCase()) {
event.preventDefault()
}
})
diff --git a/BTCPayServer/Views/UIApps/ListApps.cshtml b/BTCPayServer/Views/UIApps/ListApps.cshtml
index 43e5458..791ef34 100644
--- a/BTCPayServer/Views/UIApps/ListApps.cshtml
+++ b/BTCPayServer/Views/UIApps/ListApps.cshtml
@@ -136,4 +136,4 @@
}
</div>
-<partial name="_Confirm" model="@(new ConfirmModel("Delete app", "This app will be removed from this store.", "Delete"))" />
+<partial name="_Confirm" model="@(new ConfirmModel("Delete app", "This app will be removed from this store.", StringLocalizer["Delete"]))" />
diff --git a/BTCPayServer/Views/UIForms/FormsList.cshtml b/BTCPayServer/Views/UIForms/FormsList.cshtml
index 725411e..fa06cac 100644
--- a/BTCPayServer/Views/UIForms/FormsList.cshtml
+++ b/BTCPayServer/Views/UIForms/FormsList.cshtml
@@ -41,7 +41,7 @@
<a asp-action="ViewPublicForm" asp-route-formId="@item.Id" id="View-@item.Name" not-permission="@Policies.CanModifyStoreSettings">@item.Name</a>
</td>
<td class="actions-col" permission="@Policies.CanModifyStoreSettings">
- <a asp-action="Remove" asp-route-storeId="@item.StoreId" asp-route-id="@item.Id" id="Remove-@item.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-confirm-input="DELETE" text-translate="true">Remove</a> -
+ <a asp-action="Remove" asp-route-storeId="@item.StoreId" asp-route-id="@item.Id" id="Remove-@item.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-confirm-input="@StringLocalizer["Delete"]" text-translate="true">Remove</a> -
<a asp-action="ViewPublicForm" asp-route-formId="@item.Id" id="View-@item.Name" text-translate="true">View</a>
</td>
</tr>
@@ -59,4 +59,4 @@
</div>
</div>
-<partial name="_Confirm" model="@(new ConfirmModel("Delete form", "This form will be removed from this store.", "Delete"))" permission="@Policies.CanModifyStoreSettings" />
+<partial name="_Confirm" model="@(new ConfirmModel("Delete form", "This form will be removed from this store.", StringLocalizer["Delete"]))" permission="@Policies.CanModifyStoreSettings" />
diff --git a/BTCPayServer/Views/UILNURL/EditLightningAddress.cshtml b/BTCPayServer/Views/UILNURL/EditLightningAddress.cshtml
index 0a6d229..3d0bf83 100644
--- a/BTCPayServer/Views/UILNURL/EditLightningAddress.cshtml
+++ b/BTCPayServer/Views/UILNURL/EditLightningAddress.cshtml
@@ -15,8 +15,8 @@
@section PageFootContent {
<script>
- delegate('click', '.remove', event => {
- event.preventDefault()
+ delegate('click', '.remove', event => {
+ event.preventDefault()
const { name, value } = event.target
const confirmButton = document.getElementById('ConfirmContinue')
confirmButton.setAttribute('name', name)
@@ -48,7 +48,7 @@
var showAddForm = !ViewContext.ViewData.ModelState.IsValid || !string.IsNullOrEmpty(Model.Add?.Username) || Model.Add?.Max != null || Model.Add?.Min != null || !string.IsNullOrEmpty(Model.Add?.CurrencyCode);
var showAdvancedOptions = !string.IsNullOrEmpty(Model.Add?.CurrencyCode) || !string.IsNullOrEmpty(Model.Add?.InvoiceMetadata) || Model.Add?.Min != null || Model.Add?.Max != null;
}
-
+
<div class="collapse @(showAddForm ? "show": "")" id="AddAddress">
<div class="form-group">
<label asp-for="Add.Username" class="form-label"></label>
@@ -97,12 +97,12 @@
</div>
</div>
</div>
-
+
<div class="form-group">
<button type="submit" name="command" value="add" class="btn btn-primary">Save</button>
</div>
</div>
-
+
@if (Model.Items.Any())
{
<table class="table table-hover">
@@ -151,7 +151,7 @@
}
</td>
<td class="text-end">
- <button type="submit" title="Remove" name="command" value="@($"remove:{Model.Items[index].Username}")" class="btn btn-link px-0 remove" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The Lightning Address <strong>@Html.Encode(address)</strong> will be removed." data-confirm-input="REMOVE" text-translate="true">
+ <button type="submit" title="Remove" name="command" value="@($"remove:{Model.Items[index].Username}")" class="btn btn-link px-0 remove" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The Lightning Address <strong>@Html.Encode(address)</strong> will be removed." data-confirm-input="@StringLocalizer["Delete"]" text-translate="true">
Remove
</button>
</td>
@@ -168,4 +168,4 @@
}
</form>
-<partial name="_Confirm" model="@(new ConfirmModel("Remove Lightning Address", "This Lightning Address will be removed.", "Remove"))" />
+<partial name="_Confirm" model="@(new ConfirmModel(StringLocalizer["Remove Lightning Address"], StringLocalizer["This Lightning Address will be removed."], StringLocalizer["Delete"]))" />
diff --git a/BTCPayServer/Views/UIManage/APIKeys.cshtml b/BTCPayServer/Views/UIManage/APIKeys.cshtml
index e6c3205..c5e26e3 100644
--- a/BTCPayServer/Views/UIManage/APIKeys.cshtml
+++ b/BTCPayServer/Views/UIManage/APIKeys.cshtml
@@ -77,7 +77,7 @@
</td>
<td>
<div class="d-flex align-items-center justify-content-end gap-1">
- <a asp-action="DeleteAPIKey" asp-route-id="@keyData.Id" asp-controller="UIManage" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="Any application using the API key <strong>@Html.Encode(keyData.Label ?? keyData.Id)</strong> will immediately lose access." data-confirm-input="DELETE" text-translate="true">Delete</a>
+ <a asp-action="DeleteAPIKey" asp-route-id="@keyData.Id" asp-controller="UIManage" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="Any application using the API key <strong>@Html.Encode(keyData.Label ?? keyData.Id)</strong> will immediately lose access." data-confirm-input="@StringLocalizer["Delete"]" text-translate="true">Delete</a>
<span>-</span>
<button type="button" class="btn btn-link only-for-js p-0" data-qr="@index" text-translate="true">Show QR</button>
</div>
@@ -91,7 +91,7 @@
</div>
</div>
-<partial name="_Confirm" model="@(new ConfirmModel("Delete API key", "Any application using the API key will immediately lose access.", "Delete"))" />
+<partial name="_Confirm" model="@(new ConfirmModel(StringLocalizer["Delete API key"], StringLocalizer["Any application using the API key will immediately lose access."], StringLocalizer["Delete"]))" />
<partial name="ShowQR" />
diff --git a/BTCPayServer/Views/UIManage/Index.cshtml b/BTCPayServer/Views/UIManage/Index.cshtml
index 539ba30..b546ae0 100644
--- a/BTCPayServer/Views/UIManage/Index.cshtml
+++ b/BTCPayServer/Views/UIManage/Index.cshtml
@@ -70,7 +70,7 @@
}
<h3 class="mt-5 mb-4" text-translate="true">Delete Account</h3>
<div id="danger-zone">
- <a id="delete-user" class="btn btn-outline-danger mb-5" data-confirm-input="DELETE" data-bs-toggle="modal" data-bs-target="#ConfirmModal" asp-action="DeleteUserPost" data-description="@StringLocalizer["This action will also delete all stores, invoices, apps and data associated with the user."]" text-translate="true">Delete Account</a>
+ <a id="delete-user" class="btn btn-outline-danger mb-5" data-confirm-input="@StringLocalizer["Delete"]" data-bs-toggle="modal" data-bs-target="#ConfirmModal" asp-action="DeleteUserPost" data-description="@StringLocalizer["This action will also delete all stores, invoices, apps and data associated with the user."]" text-translate="true">Delete Account</a>
</div>
</div>
</form>
diff --git a/BTCPayServer/Views/UIManage/TwoFactorAuthentication.cshtml b/BTCPayServer/Views/UIManage/TwoFactorAuthentication.cshtml
index 860d5f1..e6984e2 100644
--- a/BTCPayServer/Views/UIManage/TwoFactorAuthentication.cshtml
+++ b/BTCPayServer/Views/UIManage/TwoFactorAuthentication.cshtml
@@ -115,11 +115,11 @@
@if (device.Type == Fido2Credential.CredentialType.FIDO2)
{
- <a asp-controller="UIFido2" asp-action="Remove" asp-route-id="@device.Id" class="btn btn-outline-danger" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-title="@StringLocalizer["Remove security device"]" data-description="@ViewLocalizer["Your account will no longer have the security device <strong>{0}</strong> as an option for two-factor authentication.", Html.Encode(name)]" data-confirm="@StringLocalizer["Remove"]" data-confirm-input="@StringLocalizer["REMOVE"]" text-translate="true">Remove</a>
+ <a asp-controller="UIFido2" asp-action="Remove" asp-route-id="@device.Id" class="btn btn-outline-danger" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-title="@StringLocalizer["Remove security device"]" data-description="@ViewLocalizer["Your account will no longer have the security device <strong>{0}</strong> as an option for two-factor authentication.", Html.Encode(name)]" data-confirm="@StringLocalizer["Delete"]" data-confirm-input="@StringLocalizer["Delete"]" text-translate="true">Remove</a>
}
else if (device.Type == Fido2Credential.CredentialType.LNURLAuth)
{
- <a asp-controller="UILNURLAuth" asp-action="Remove" asp-route-id="@device.Id" class="btn btn-outline-danger" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-title="@StringLocalizer["Remove Lightning security"]" data-description="@ViewLocalizer["Your account will no longer be linked to the lightning node <strong>{0}</strong> as an option for two-factor authentication.", Html.Encode(name)]" data-confirm="@StringLocalizer["Remove"]" data-confirm-input="@StringLocalizer["REMOVE"]" text-translate="true">Remove</a>
+ <a asp-controller="UILNURLAuth" asp-action="Remove" asp-route-id="@device.Id" class="btn btn-outline-danger" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-title="@StringLocalizer["Remove Lightning security"]" data-description="@ViewLocalizer["Your account will no longer be linked to the lightning node <strong>{0}</strong> as an option for two-factor authentication.", Html.Encode(name)]" data-confirm="@StringLocalizer["Delete"]" data-confirm-input="@StringLocalizer["Delete"]" text-translate="true">Remove</a>
}
</div>
}
@@ -131,7 +131,7 @@
<input type="text" class="form-control" name="Name" placeholder="@StringLocalizer["Security device name"]"/>
<select asp-items="@Html.GetEnumSelectList<Fido2Credential.CredentialType>()" class="form-select w-auto" name="type"></select>
<button id="btn-add" type="submit" class="btn btn-primary" text-translate="true">
- Add
+ Add
</button>
</div>
</form>
diff --git a/BTCPayServer/Views/UIPayoutProcessors/ConfigureStorePayoutProcessors.cshtml b/BTCPayServer/Views/UIPayoutProcessors/ConfigureStorePayoutProcessors.cshtml
index e14f611..4c96672 100644
--- a/BTCPayServer/Views/UIPayoutProcessors/ConfigureStorePayoutProcessors.cshtml
+++ b/BTCPayServer/Views/UIPayoutProcessors/ConfigureStorePayoutProcessors.cshtml
@@ -44,7 +44,7 @@
else
{
<a id="Configure-@conf.Key" href="@processorsView.Factory.ConfigureLink(storeId, conf.Key, Context.Request)" text-translate="true">Modify</a>
-
+
@if (await processorsView.Factory.CanRemove())
{
<span>-</span>
@@ -67,7 +67,7 @@
</div>
</div>
-<partial name="_Confirm" model="@(new ConfirmModel("Delete payout processor", "This payout processor will be removed from this store.", "Delete"))" permission="@Policies.CanModifyStoreSettings" />
+<partial name="_Confirm" model="@(new ConfirmModel("Delete payout processor", "This payout processor will be removed from this store.", StringLocalizer["Delete"]))" permission="@Policies.CanModifyStoreSettings" />
@section PageFootContent {
<partial name="_ValidationScriptsPartial"/>
}
diff --git a/BTCPayServer/Views/UIServer/DynamicDnsServices.cshtml b/BTCPayServer/Views/UIServer/DynamicDnsServices.cshtml
index 55fa9c1..b95cf9d 100644
--- a/BTCPayServer/Views/UIServer/DynamicDnsServices.cshtml
+++ b/BTCPayServer/Views/UIServer/DynamicDnsServices.cshtml
@@ -32,11 +32,11 @@
<div class="form-group">
<p text-translate="true">Dynamic DNS allows you to have a stable DNS name pointing to your server, even if your IP address changes regularly. This is recommended if you are hosting BTCPay Server at home and wish to have a clearnet domain to access your server.</p>
<p>
- Note that you need to properly configure your NAT and BTCPay Server installation to get the HTTPS certificate.
+ Note that you need to properly configure your NAT and BTCPay Server installation to get the HTTPS certificate.
See the documentation for <a href="https://docs.btcpayserver.org/Deployment/DynamicDNS/" target="_blank" rel="noreferrer noopener">more information</a>.
</p>
</div>
-
+
@if (Model.Any())
{
<div class="table-responsive-md">
@@ -68,7 +68,7 @@
<td class="text-end">
<a asp-action="DynamicDnsService" asp-route-hostname="@service.Settings.Hostname" text-translate="true">Edit</a>
<span> - </span>
- <a asp-action="DeleteDynamicDnsService" asp-route-hostname="@service.Settings.Hostname" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="Deleting the dynamic DNS service for <strong>@Html.Encode(service.Settings.Hostname)</strong> means your BTCPay Server will stop updating the associated DNS record periodically." data-confirm-input="DELETE" text-translate="true">Delete</a>
+ <a asp-action="DeleteDynamicDnsService" asp-route-hostname="@service.Settings.Hostname" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="Deleting the dynamic DNS service for <strong>@Html.Encode(service.Settings.Hostname)</strong> means your BTCPay Server will stop updating the associated DNS record periodically." data-confirm-input="@StringLocalizer["Delete"]" text-translate="true">Delete</a>
</td>
</tr>
}
@@ -85,5 +85,5 @@
</div>
</div>
-<partial name="_Confirm" model="@(new ConfirmModel("Delete dynamic DNS service", "Deleting the dynamic DNS service means your BTCPay Server will stop updating the associated DNS record periodically.", "Delete"))" />
+<partial name="_Confirm" model="@(new ConfirmModel("Delete dynamic DNS service", "Deleting the dynamic DNS service means your BTCPay Server will stop updating the associated DNS record periodically.", StringLocalizer["Delete"]))" />
diff --git a/BTCPayServer/Views/UIServer/ListDictionaries.cshtml b/BTCPayServer/Views/UIServer/ListDictionaries.cshtml
index 476d758..54f3695 100644
--- a/BTCPayServer/Views/UIServer/ListDictionaries.cshtml
+++ b/BTCPayServer/Views/UIServer/ListDictionaries.cshtml
@@ -55,7 +55,7 @@
}
@if (v.Editable && !v.IsSelected)
{
- <a id="Delete-@v.DictionaryName" asp-action="DeleteDictionary" asp-route-dictionary="@v.DictionaryName" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The dictionary <b>@Html.Encode(v.DictionaryName)</b> will be removed from this server." data-confirm-input="DELETE" text-translate="true">Remove</a>
+ <a id="Delete-@v.DictionaryName" asp-action="DeleteDictionary" asp-route-dictionary="@v.DictionaryName" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The dictionary <b>@Html.Encode(v.DictionaryName)</b> will be removed from this server." data-confirm-input="@StringLocalizer["Delete"]" text-translate="true">Remove</a>
}
</div>
</td>
@@ -63,5 +63,5 @@
}
</tbody>
</table>
- <partial name="_Confirm" model="@(new ConfirmModel("Delete dictionary", "This dictionary will be removed from this server.", "Delete"))" />
+ <partial name="_Confirm" model="@(new ConfirmModel(StringLocalizer["Delete dictionary"], StringLocalizer["This dictionary will be removed from this server."], StringLocalizer["Delete"]))" />
</div>
diff --git a/BTCPayServer/Views/UIServer/ListUsers.cshtml b/BTCPayServer/Views/UIServer/ListUsers.cshtml
index 2756c95..6acf97f 100644
--- a/BTCPayServer/Views/UIServer/ListUsers.cshtml
+++ b/BTCPayServer/Views/UIServer/ListUsers.cshtml
@@ -166,5 +166,5 @@
<vc:pager view-model="Model"></vc:pager>
-<partial name="_Confirm" model="@(new ConfirmModel("Send verification email", $"This will send a verification email to the user.", "Send"))" />
+<partial name="_Confirm" model="@(new ConfirmModel(StringLocalizer["Send verification email"], StringLocalizer["This will send a verification email to the user."], StringLocalizer["Send"]))" />
<partial name="ShowQR" />
diff --git a/BTCPayServer/Views/UIServer/SSHService.cshtml b/BTCPayServer/Views/UIServer/SSHService.cshtml
index 5ab50fd..46f79b3 100644
--- a/BTCPayServer/Views/UIServer/SSHService.cshtml
+++ b/BTCPayServer/Views/UIServer/SSHService.cshtml
@@ -74,7 +74,7 @@
</div>
</div>
-<partial name="_Confirm" model="@(new ConfirmModel("Disable modification of SSH settings", "This action is permanent and will remove the ability to change the SSH settings via the BTCPay Server user interface.", "Disable"))"/>
+<partial name="_Confirm" model="@(new ConfirmModel(StringLocalizer["Disable modification of SSH settings"], StringLocalizer["This action is permanent and will remove the ability to change the SSH settings via the BTCPay Server user interface."], StringLocalizer["Disable"]))"/>
@section PageFootContent {
<script>
diff --git a/BTCPayServer/Views/UIStores/ListTokens.cshtml b/BTCPayServer/Views/UIStores/ListTokens.cshtml
index 87a8670..bac083c 100644
--- a/BTCPayServer/Views/UIStores/ListTokens.cshtml
+++ b/BTCPayServer/Views/UIStores/ListTokens.cshtml
@@ -32,7 +32,7 @@
<span text-translate="true">To generate Greenfield API keys, please</span>
<a asp-controller="UIManage" asp-action="APIKeys" text-translate="true">click here</a>.
</p>
-
+
<div class="d-flex align-items-center justify-content-between mt-5 mb-3">
<h3 class="mb-0">@ViewData["Title"]</h3>
<a id="CreateNewToken" asp-action="CreateToken" class="btn btn-primary" role="button" asp-route-storeId="@Context.GetRouteValue("storeId")" permission="@Policies.CanModifyStoreSettings" text-translate="true">
@@ -102,4 +102,4 @@
</div>
</div>
-<partial name="_Confirm" model="@(new ConfirmModel("Revoke access token", "The access token will be revoked. Do you wish to continue?", "Revoke"))" permission="@Policies.CanModifyStoreSettings" />
+<partial name="_Confirm" model="@(new ConfirmModel(StringLocalizer["Revoke access token"], StringLocalizer["The access token will be revoked. Do you wish to continue?"], StringLocalizer["Revoke"]))" permission="@Policies.CanModifyStoreSettings" />
diff --git a/BTCPayServer/Views/UIStores/StoreUsers.cshtml b/BTCPayServer/Views/UIStores/StoreUsers.cshtml
index c983016..bedb708 100644
--- a/BTCPayServer/Views/UIStores/StoreUsers.cshtml
+++ b/BTCPayServer/Views/UIStores/StoreUsers.cshtml
@@ -24,7 +24,7 @@
<div class="row">
<div class="col-xxl-constrain col-xl-8">
<p>@ViewLocalizer["Give other registered BTCPay Server users access to your store. See the {0} for granted permissions.", Html.ActionLink(StringLocalizer["roles"], "ListRoles", "UIStores", new { storeId })]</p>
-
+
@if (!ViewContext.ModelState.IsValid)
{
<div asp-validation-summary="All" class="@(ViewContext.ModelState.ErrorCount.Equals(1) ? "no-marker" : "")"></div>
@@ -56,7 +56,7 @@
<td class="actions-col" permission="@Policies.CanModifyStoreSettings">
<div class="d-inline-flex align-items-center gap-3">
<a asp-action="UpdateStoreUser" asp-route-storeId="@Model.StoreId" asp-route-userId="@user.Id" data-bs-toggle="modal" data-bs-target="#EditModal" data-user-email="@user.Email" data-user-role="@user.Role" text-translate="true">Change Role</a>
- <a asp-action="DeleteStoreUser" asp-route-storeId="@Model.StoreId" asp-route-userId="@user.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="@StringLocalizer["This action will prevent {0} from accessing this store and its settings.", Html.Encode(user.Email)]" data-confirm-input="@StringLocalizer["REMOVE"]" text-translate="true">Remove</a>
+ <a asp-action="DeleteStoreUser" asp-route-storeId="@Model.StoreId" asp-route-userId="@user.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="@StringLocalizer["This action will prevent {0} from accessing this store and its settings.", Html.Encode(user.Email)]" data-confirm-input="@StringLocalizer["Delete"]" text-translate="true">Remove</a>
</div>
</td>
</tr>
@@ -104,7 +104,7 @@
const action = $target.dataset.action || ($target.nodeName === 'A'
? $target.getAttribute('href')
: $target.form.getAttribute('action'))
-
+
if ($form && !$form.hasAttribute('action')) $form.setAttribute('action', action)
if (userEmail) $email.textContent = userEmail
if (userRole) $role.value = userRole
diff --git a/BTCPayServer/Views/UIStores/WalletSettings.cshtml b/BTCPayServer/Views/UIStores/WalletSettings.cshtml
index 5e6b355..d1508c7 100644
--- a/BTCPayServer/Views/UIStores/WalletSettings.cshtml
+++ b/BTCPayServer/Views/UIStores/WalletSettings.cshtml
@@ -67,8 +67,8 @@
data-bs-target="#ConfirmModal"
data-title="@StringLocalizer["Remove {0} wallet", Model.CryptoCode]"
data-description="@ViewData["RemoveDescription"]"
- data-confirm="@StringLocalizer["Remove"]"
- data-confirm-input="@StringLocalizer["REMOVE"]"
+ data-confirm="@StringLocalizer["Delete"]"
+ data-confirm-input="@StringLocalizer["Delete"]"
text-translate="true">Remove wallet</button>
</form>
</div>
@@ -176,7 +176,7 @@
}
</form>
-<partial name="_Confirm" model="@(new ConfirmModel(StringLocalizer["{0} wallet", Model.CryptoCode], StringLocalizer["Change"], "Update"))" />
+<partial name="_Confirm" model="@(new ConfirmModel(StringLocalizer["{0} wallet", Model.CryptoCode], StringLocalizer["Change"], StringLocalizer["Update"]))" />
<partial name="ShowQR"/>
@section PageFootContent {
diff --git a/BTCPayServer/Views/UIWallets/WalletLabels.cshtml b/BTCPayServer/Views/UIWallets/WalletLabels.cshtml
index a5baeab..d8024da 100644
--- a/BTCPayServer/Views/UIWallets/WalletLabels.cshtml
+++ b/BTCPayServer/Views/UIWallets/WalletLabels.cshtml
@@ -49,7 +49,7 @@
</tbody>
</table>
</div>
- <partial name="_Confirm" model="@(new ConfirmModel(StringLocalizer["Remove label"], StringLocalizer["This label will be removed from this wallet and its associated transactions."], StringLocalizer["Remove"]))" />
+ <partial name="_Confirm" model="@(new ConfirmModel(StringLocalizer["Remove label"], StringLocalizer["This label will be removed from this wallet and its associated transactions."], StringLocalizer["Delete"]))" />
}
else
{
Why this scored 20/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.