diff --git a/BTCPayServer.Tests/PlaywrightTests.cs b/BTCPayServer.Tests/PlaywrightTests.cs
index 617450bd3..128a1ae5e 100644
--- a/BTCPayServer.Tests/PlaywrightTests.cs
+++ b/BTCPayServer.Tests/PlaywrightTests.cs
@@ -2581,6 +2581,230 @@ namespace BTCPayServer.Tests
await s.FindAlertMessage(StatusMessageModel.StatusSeverity.Error, "The user is the last owner. Their role cannot be changed.");
}
+
+ [Fact]
+ [Trait("Playwright", "Playwright")]
+ public async Task CanUseRoleManager()
+ {
+ await using var s = CreatePlaywrightTester(newDb: true);
+ await s.StartAsync();
+ await s.RegisterNewUser(true);
+ await s.GoToHome();
+ await s.GoToServer(ServerNavPages.Roles);
+ var existingServerRoles = await s.Page.Locator("table tr").AllAsync();
+ Assert.Equal(5, existingServerRoles.Count);
+ ILocator ownerRow = null;
+ ILocator managerRow = null;
+ ILocator employeeRow = null;
+ ILocator guestRow = null;
+ foreach (var roleItem in existingServerRoles)
+ {
+ var text = await roleItem.TextContentAsync();
+ if (text.Contains("owner", StringComparison.InvariantCultureIgnoreCase))
+ {
+ ownerRow = roleItem;
+ }
+ else if (text.Contains("manager", StringComparison.InvariantCultureIgnoreCase))
+ {
+ managerRow = roleItem;
+ }
+ else if (text.Contains("employee", StringComparison.InvariantCultureIgnoreCase))
+ {
+ employeeRow = roleItem;
+ }
+ else if (text.Contains("guest", StringComparison.InvariantCultureIgnoreCase))
+ {
+ guestRow = roleItem;
+ }
+ }
+
+ Assert.NotNull(ownerRow);
+ Assert.NotNull(managerRow);
+ Assert.NotNull(employeeRow);
+ Assert.NotNull(guestRow);
+
+ var ownerBadges = await ownerRow.Locator(".badge").AllAsync();
+ var ownerBadgeTexts = await Task.WhenAll(ownerBadges.Select(async element => await element.TextContentAsync()));
+ Assert.Contains(ownerBadgeTexts, text => text.Equals("Default", StringComparison.InvariantCultureIgnoreCase));
+ Assert.Contains(ownerBadgeTexts, text => text.Equals("Server-wide", StringComparison.InvariantCultureIgnoreCase));
+
+ var managerBadges = await managerRow.Locator(".badge").AllAsync();
+ var managerBadgeTexts = await Task.WhenAll(managerBadges.Select(async element => await element.TextContentAsync()));
+ Assert.DoesNotContain(managerBadgeTexts, text => text.Equals("Default", StringComparison.InvariantCultureIgnoreCase));
+ Assert.Contains(managerBadgeTexts, text => text.Equals("Server-wide", StringComparison.InvariantCultureIgnoreCase));
+
+ var employeeBadges = await employeeRow.Locator(".badge").AllAsync();
+ var employeeBadgeTexts = await Task.WhenAll(employeeBadges.Select(async element => await element.TextContentAsync()));
+ Assert.DoesNotContain(employeeBadgeTexts, text => text.Equals("Default", StringComparison.InvariantCultureIgnoreCase));
+ Assert.Contains(employeeBadgeTexts, text => text.Equals("Server-wide", StringComparison.InvariantCultureIgnoreCase));
+
+ var guestBadges = await guestRow.Locator(".badge").AllAsync();
+ var guestBadgeTexts = await Task.WhenAll(guestBadges.Select(async element => await element.TextContentAsync()));
+ Assert.DoesNotContain(guestBadgeTexts, text => text.Equals("Default", StringComparison.InvariantCultureIgnoreCase));
+ Assert.Contains(guestBadgeTexts, text => text.Equals("Server-wide", StringComparison.InvariantCultureIgnoreCase));
+ await guestRow.Locator("#SetDefault").ClickAsync();
+ await s.FindAlertMessage(partialText: "Role set default");
+
+ existingServerRoles = await s.Page.Locator("table tr").AllAsync();
+ foreach (var roleItem in existingServerRoles)
+ {
+ var text = await roleItem.TextContentAsync();
+ if (text.Contains("owner", StringComparison.InvariantCultureIgnoreCase))
+ {
+ ownerRow = roleItem;
+ }
+ else if (text.Contains("guest", StringComparison.InvariantCultureIgnoreCase))
+ {
+ guestRow = roleItem;
+ }
+ }
+ guestBadges = await guestRow.Locator(".badge").AllAsync();
+ var guestBadgeTexts2 = await Task.WhenAll(guestBadges.Select(async element => await element.TextContentAsync()));
+ Assert.Contains(guestBadgeTexts2, text => text.Equals("Default", StringComparison.InvariantCultureIgnoreCase));
+
+ ownerBadges = await ownerRow.Locator(".badge").AllAsync();
+ var ownerBadgeTexts2 = await Task.WhenAll(ownerBadges.Select(async element => await element.TextContentAsync()));
+ Assert.DoesNotContain(ownerBadgeTexts2, text => text.Equals("Default", StringComparison.InvariantCultureIgnoreCase));
+ await ownerRow.Locator("#SetDefault").ClickAsync();
+
+ await s.FindAlertMessage(partialText: "Role set default");
+
+ await s.CreateNewStore();
+ await s.GoToStore(StoreNavPages.Roles);
+ existingServerRoles = await s.Page.Locator("table tr").AllAsync();
+ Assert.Equal(5, existingServerRoles.Count);
+ var serverRoleTexts = await Task.WhenAll(existingServerRoles.Select(async element => await element.TextContentAsync()));
+ Assert.Equal(4, serverRoleTexts.Count(text => text.Contains("Server-wide", StringComparison.InvariantCultureIgnoreCase)));
+
+ foreach (var roleItem in existingServerRoles)
+ {
+ var text = await roleItem.TextContentAsync();
+ if (text.Contains("owner", StringComparison.InvariantCultureIgnoreCase))
+ {
+ ownerRow = roleItem;
+ break;
+ }
+ }
+
+ await ownerRow.Locator("text=Remove").ClickAsync();
+ await s.Page.WaitForLoadStateAsync();
+ Assert.DoesNotContain("ConfirmContinue", await s.Page.ContentAsync());
+ await s.Page.GoBackAsync();
+ existingServerRoles = await s.Page.Locator("table tr").AllAsync();
+ foreach (var roleItem in existingServerRoles)
+ {
+ var text = await roleItem.TextContentAsync();
+ if (text.Contains("guest", StringComparison.InvariantCultureIgnoreCase))
+ {
+ guestRow = roleItem;
+ break;
+ }
+ }
+
+ await guestRow.Locator("text=Remove").ClickAsync();
+ await s.Page.ClickAsync("#ConfirmContinue");
+ await s.FindAlertMessage();
+
+ await s.GoToStore(StoreNavPages.Roles);
+ await s.ClickPagePrimary();
+
+ Assert.Contains("Create role", await s.Page.ContentAsync());
+ await s.ClickPagePrimary();
+ await s.Page.Locator("#Role").FillAsync("store role");
+ await s.ClickPagePrimary();
+ await s.FindAlertMessage();
+
+ existingServerRoles = await s.Page.Locator("table tr").AllAsync();
+ foreach (var roleItem in existingServerRoles)
+ {
+ var text = await roleItem.TextContentAsync();
+ if (text.Contains("store role", StringComparison.InvariantCultureIgnoreCase))
+ {
+ guestRow = roleItem;
+ break;
+ }
+ }
+
+ guestBadges = await guestRow.Locator(".badge").AllAsync();
+ var guestBadgeTexts3 = await Task.WhenAll(guestBadges.Select(async element => await element.TextContentAsync()));
+ Assert.DoesNotContain(guestBadgeTexts3, text => text.Equals("server-wide", StringComparison.InvariantCultureIgnoreCase));
+ await s.GoToStore(StoreNavPages.Users);
+ var options = await s.Page.Locator("#Role option").AllAsync();
+ Assert.Equal(4, options.Count);
+ var optionTexts = await Task.WhenAll(options.Select(async element => await element.TextContentAsync()));
+ Assert.Contains(optionTexts, text => text.Equals("store role", StringComparison.InvariantCultureIgnoreCase));
+ await s.CreateNewStore();
+ await s.GoToStore(StoreNavPages.Roles);
+ existingServerRoles = await s.Page.Locator("table tr").AllAsync();
+ Assert.Equal(4, existingServerRoles.Count);
+ var serverRoleTexts2 = await Task.WhenAll(existingServerRoles.Select(async element => await element.TextContentAsync()));
+ Assert.Equal(3, serverRoleTexts2.Count(text => text.Contains("Server-wide", StringComparison.InvariantCultureIgnoreCase)));
+ Assert.Equal(0, serverRoleTexts2.Count(text => text.Contains("store role", StringComparison.InvariantCultureIgnoreCase)));
+ await s.GoToStore(StoreNavPages.Users);
+ options = await s.Page.Locator("#Role option").AllAsync();
+ Assert.Equal(3, options.Count);
+ var optionTexts2 = await Task.WhenAll(options.Select(async element => await element.TextContentAsync()));
+ Assert.DoesNotContain(optionTexts2, text => text.Equals("store role", StringComparison.InvariantCultureIgnoreCase));
+
+ await s.Page.Locator("#Email").FillAsync(s.AsTestAccount().Email);
+ await s.Page.Locator("#Role").SelectOptionAsync("Owner");
+ await s.Page.ClickAsync("#AddUser");
+ Assert.Contains("The user already has the role Owner.", await s.Page.Locator(".validation-summary-errors").TextContentAsync());
+ await s.Page.Locator("#Role").SelectOptionAsync("Manager");
+ await s.Page.ClickAsync("#AddUser");
+ Assert.Contains("The user is the last owner. Their role cannot be changed.", await s.Page.Locator(".validation-summary-errors").TextContentAsync());
+
+ await s.GoToStore(StoreNavPages.Roles);
+ await s.ClickPagePrimary();
+ await s.Page.Locator("#Role").FillAsync("Malice");
+
+ await s.Page.EvaluateAsync($"document.getElementById('Policies')['{Policies.CanModifyServerSettings}']=new Option('{Policies.CanModifyServerSettings}', '{Policies.CanModifyServerSettings}', true,true);");
+
+ await s.ClickPagePrimary();
+ await s.FindAlertMessage();
+ Assert.Contains("Malice", await s.Page.ContentAsync());
+ Assert.DoesNotContain(Policies.CanModifyServerSettings, await s.Page.ContentAsync());
+ }
+
+ [Fact]
+ [Trait("Playwright", "Playwright")]
+ public async Task CanSigninWithLoginCode()
+ {
+ await using var s = CreatePlaywrightTester();
+ await s.StartAsync();
+ var user = await s.RegisterNewUser();
+ await s.GoToHome();
+ await s.GoToProfile(ManageNavPages.LoginCodes);
+
+ string code = null;
+ await s.Page.WaitForSelectorAsync("#LoginCode .qr-code");
+ code = await s.Page.Locator("#LoginCode .qr-code").GetAttributeAsync("alt");
+ string prevCode = code;
+ await s.Page.ReloadAsync();
+ await s.Page.WaitForSelectorAsync("#LoginCode .qr-code");
+ code = await s.Page.Locator("#LoginCode .qr-code").GetAttributeAsync("alt");
+ Assert.NotEqual(prevCode, code);
+ await s.Page.WaitForSelectorAsync("#LoginCode .qr-code");
+ code = await s.Page.Locator("#LoginCode .qr-code").GetAttributeAsync("alt");
+ await s.Logout();
+ await s.GoToLogin();
+ await s.Page.EvaluateAsync("document.getElementById('LoginCode').value = 'bad code'");
+ await s.Page.EvaluateAsync("document.getElementById('logincode-form').submit()");
+ await s.Page.WaitForLoadStateAsync();
+
+ await s.GoToLogin();
+ await s.Page.EvaluateAsync($"document.getElementById('LoginCode').value = '{code}'");
+ await s.Page.EvaluateAsync("document.getElementById('logincode-form').submit()");
+ await s.Page.WaitForLoadStateAsync();
+ await s.Page.WaitForLoadStateAsync();
+
+ await s.CreateNewStore();
+ await s.GoToHome();
+ await s.Page.WaitForLoadStateAsync();
+ await s.Page.WaitForLoadStateAsync();
+ var content = await s.Page.ContentAsync();
+ Assert.Contains(user, content);
+ }
}
}
diff --git a/BTCPayServer.Tests/SeleniumTests.cs b/BTCPayServer.Tests/SeleniumTests.cs
index 6da6f99da..12fd1d552 100644
--- a/BTCPayServer.Tests/SeleniumTests.cs
+++ b/BTCPayServer.Tests/SeleniumTests.cs
@@ -1353,34 +1353,6 @@ namespace BTCPayServer.Tests
Assert.Contains(lnUsername, source);
}
- [Fact]
- [Trait("Selenium", "Selenium")]
- public async Task CanSigninWithLoginCode()
- {
- using var s = CreateSeleniumTester();
- await s.StartAsync();
- var user = s.RegisterNewUser();
- s.GoToHome();
- s.GoToProfile(ManageNavPages.LoginCodes);
-
- string code = null;
- TestUtils.Eventually(() => { code = s.Driver.FindElement(By.CssSelector("#LoginCode .qr-code")).GetAttribute("alt"); });
- string prevCode = code;
- await s.Driver.Navigate().RefreshAsync();
- TestUtils.Eventually(() => { code = s.Driver.FindElement(By.CssSelector("#LoginCode .qr-code")).GetAttribute("alt"); });
- Assert.NotEqual(prevCode, code);
- TestUtils.Eventually(() => { code = s.Driver.FindElement(By.CssSelector("#LoginCode .qr-code")).GetAttribute("alt"); });
- s.Logout();
- s.GoToLogin();
- s.Driver.SetAttribute("LoginCode", "value", "bad code");
- s.Driver.InvokeJSFunction("logincode-form", "submit");
-
- s.Driver.SetAttribute("LoginCode", "value", code);
- s.Driver.InvokeJSFunction("logincode-form", "submit");
- s.GoToHome();
- Assert.Contains(user, s.Driver.PageSource);
- }
-
// For god know why, selenium have problems clicking on the save button, resulting in ultimate hacks
// to make it works.
private void SudoForceSaveLightningSettingsRightNowAndFast(SeleniumTester s, string cryptoCode)
@@ -1399,175 +1371,6 @@ retry:
}
}
- [Fact]
- [Trait("Selenium", "Selenium")]
- public async Task CanUseRoleManager()
- {
- using var s = CreateSeleniumTester(newDb: true);
- await s.StartAsync();
- s.RegisterNewUser(true);
- s.GoToHome();
- s.GoToServer(ServerNavPages.Roles);
- var existingServerRoles = s.Driver.FindElement(By.CssSelector("table")).FindElements(By.CssSelector("tr"));
- Assert.Equal(5, existingServerRoles.Count);
- IWebElement ownerRow = null;
- IWebElement managerRow = null;
- IWebElement employeeRow = null;
- IWebElement guestRow = null;
- foreach (var roleItem in existingServerRoles)
- {
- if (roleItem.Text.Contains("owner", StringComparison.InvariantCultureIgnoreCase))
- {
- ownerRow = roleItem;
- }
- else if (roleItem.Text.Contains("manager", StringComparison.InvariantCultureIgnoreCase))
- {
- managerRow = roleItem;
- }
- else if (roleItem.Text.Contains("employee", StringComparison.InvariantCultureIgnoreCase))
- {
- employeeRow = roleItem;
- }
- else if (roleItem.Text.Contains("guest", StringComparison.InvariantCultureIgnoreCase))
- {
- guestRow = roleItem;
- }
- }
-
- Assert.NotNull(ownerRow);
- Assert.NotNull(managerRow);
- Assert.NotNull(employeeRow);
- Assert.NotNull(guestRow);
-
- var ownerBadges = ownerRow.FindElements(By.CssSelector(".badge"));
- Assert.Contains(ownerBadges, element => element.Text.Equals("Default", StringComparison.InvariantCultureIgnoreCase));
- Assert.Contains(ownerBadges, element => element.Text.Equals("Server-wide", StringComparison.InvariantCultureIgnoreCase));
-
- var managerBadges = managerRow.FindElements(By.CssSelector(".badge"));
- Assert.DoesNotContain(managerBadges, element => element.Text.Equals("Default", StringComparison.InvariantCultureIgnoreCase));
- Assert.Contains(managerBadges, element => element.Text.Equals("Server-wide", StringComparison.InvariantCultureIgnoreCase));
-
- var employeeBadges = employeeRow.FindElements(By.CssSelector(".badge"));
- Assert.DoesNotContain(employeeBadges, element => element.Text.Equals("Default", StringComparison.InvariantCultureIgnoreCase));
- Assert.Contains(employeeBadges, element => element.Text.Equals("Server-wide", StringComparison.InvariantCultureIgnoreCase));
-
- var guestBadges = guestRow.FindElements(By.CssSelector(".badge"));
- Assert.DoesNotContain(guestBadges, element => element.Text.Equals("Default", StringComparison.InvariantCultureIgnoreCase));
- Assert.Contains(guestBadges, element => element.Text.Equals("Server-wide", StringComparison.InvariantCultureIgnoreCase));
- guestRow.FindElement(By.Id("SetDefault")).Click();
- Assert.Contains("Role set default", s.FindAlertMessage().Text);
-
- existingServerRoles = s.Driver.FindElement(By.CssSelector("table")).FindElements(By.CssSelector("tr"));
- foreach (var roleItem in existingServerRoles)
- {
- if (roleItem.Text.Contains("owner", StringComparison.InvariantCultureIgnoreCase))
- {
- ownerRow = roleItem;
- }
- else if (roleItem.Text.Contains("guest", StringComparison.InvariantCultureIgnoreCase))
- {
- guestRow = roleItem;
- }
- }
- guestBadges = guestRow.FindElements(By.CssSelector(".badge"));
- Assert.Contains(guestBadges, element => element.Text.Equals("Default", StringComparison.InvariantCultureIgnoreCase));
-
- ownerBadges = ownerRow.FindElements(By.CssSelector(".badge"));
- Assert.DoesNotContain(ownerBadges, element => element.Text.Equals("Default", StringComparison.InvariantCultureIgnoreCase));
- ownerRow.FindElement(By.Id("SetDefault")).Click();
- s.FindAlertMessage();
-
- Assert.Contains("Role set default", s.FindAlertMessage().Text);
-
- s.CreateNewStore();
- s.GoToStore(StoreNavPages.Roles);
- var existingStoreRoles = s.Driver.FindElement(By.CssSelector("table")).FindElements(By.CssSelector("tr"));
- Assert.Equal(5, existingStoreRoles.Count);
- Assert.Equal(4, existingStoreRoles.Count(element => element.Text.Contains("Server-wide", StringComparison.InvariantCultureIgnoreCase)));
-
- foreach (var roleItem in existingStoreRoles)
- {
- if (roleItem.Text.Contains("owner", StringComparison.InvariantCultureIgnoreCase))
- {
- ownerRow = roleItem;
- break;
- }
- }
-
- ownerRow.FindElement(By.LinkText("Remove")).Click();
- Assert.DoesNotContain("ConfirmContinue", s.Driver.PageSource);
- s.Driver.Navigate().Back();
- existingStoreRoles = s.Driver.FindElement(By.CssSelector("table")).FindElements(By.CssSelector("tr"));
- foreach (var roleItem in existingStoreRoles)
- {
- if (roleItem.Text.Contains("guest", StringComparison.InvariantCultureIgnoreCase))
- {
- guestRow = roleItem;
- break;
- }
- }
-
- guestRow.FindElement(By.LinkText("Remove")).Click();
- s.Driver.FindElement(By.Id("ConfirmContinue")).Click();
- s.FindAlertMessage();
-
- s.GoToStore(StoreNavPages.Roles);
- s.ClickPagePrimary();
-
- Assert.Contains("Create role", s.Driver.PageSource);
- s.ClickPagePrimary();
- s.Driver.FindElement(By.Id("Role")).SendKeys("store role");
- s.ClickPagePrimary();
- s.FindAlertMessage();
-
- existingStoreRoles = s.Driver.FindElement(By.CssSelector("table")).FindElements(By.CssSelector("tr"));
- foreach (var roleItem in existingStoreRoles)
- {
- if (roleItem.Text.Contains("store role", StringComparison.InvariantCultureIgnoreCase))
- {
- guestRow = roleItem;
- break;
- }
- }
-
- guestBadges = guestRow.FindElements(By.CssSelector(".badge"));
- Assert.DoesNotContain(guestBadges, element => element.Text.Equals("server-wide", StringComparison.InvariantCultureIgnoreCase));
- s.GoToStore(StoreNavPages.Users);
- var options = s.Driver.FindElements(By.CssSelector("#Role option"));
- Assert.Equal(4, options.Count);
- Assert.Contains(options, element => element.Text.Equals("store role", StringComparison.InvariantCultureIgnoreCase));
- s.CreateNewStore();
- s.GoToStore(StoreNavPages.Roles);
- existingStoreRoles = s.Driver.FindElement(By.CssSelector("table")).FindElements(By.CssSelector("tr"));
- Assert.Equal(4, existingStoreRoles.Count);
- Assert.Equal(3, existingStoreRoles.Count(element => element.Text.Contains("Server-wide", StringComparison.InvariantCultureIgnoreCase)));
- Assert.Equal(0, existingStoreRoles.Count(element => element.Text.Contains("store role", StringComparison.InvariantCultureIgnoreCase)));
- s.GoToStore(StoreNavPages.Users);
- options = s.Driver.FindElements(By.CssSelector("#Role option"));
- Assert.Equal(3, options.Count);
- Assert.DoesNotContain(options, element => element.Text.Equals("store role", StringComparison.InvariantCultureIgnoreCase));
-
- s.Driver.FindElement(By.Id("Email")).SendKeys(s.AsTestAccount().Email);
- s.Driver.FindElement(By.Id("Role")).SendKeys("owner");
- s.Driver.FindElement(By.Id("AddUser")).Click();
- Assert.Contains("The user already has the role Owner.", s.Driver.FindElement(By.CssSelector(".validation-summary-errors")).Text);
- s.Driver.FindElement(By.Id("Role")).SendKeys("manager");
- s.Driver.FindElement(By.Id("AddUser")).Click();
- Assert.Contains("The user is the last owner. Their role cannot be changed.", s.Driver.FindElement(By.CssSelector(".validation-summary-errors")).Text);
-
- s.GoToStore(StoreNavPages.Roles);
- s.ClickPagePrimary();
- s.Driver.FindElement(By.Id("Role")).SendKeys("Malice");
-
- s.Driver.ExecuteJavaScript($"document.getElementById('Policies')['{Policies.CanModifyServerSettings}']=new Option('{Policies.CanModifyServerSettings}', '{Policies.CanModifyServerSettings}', true,true);");
-
- s.ClickPagePrimary();
- s.FindAlertMessage();
- Assert.Contains("Malice",s.Driver.PageSource);
- Assert.DoesNotContain(Policies.CanModifyServerSettings,s.Driver.PageSource);
- }
-
-
private static string AssertUrlHasPairingCode(SeleniumTester s)
{
var regex = Regex.Match(new Uri(s.Driver.Url, UriKind.Absolute).Query, "pairingCode=([^&]*)");
diff --git a/BTCPayServer/Controllers/UIStoresController.Roles.cs b/BTCPayServer/Controllers/UIStoresController.Roles.cs
index 50069038c..01f73d7b0 100644
--- a/BTCPayServer/Controllers/UIStoresController.Roles.cs
+++ b/BTCPayServer/Controllers/UIStoresController.Roles.cs
@@ -122,7 +122,11 @@ public partial class UIStoresController
[FromServices] StoreRepository storeRepository,
string role)
{
- var roleData = await storeRepository.GetStoreRole(new StoreRoleId(storeId, role), true);
+ var roleId = await storeRepository.ResolveStoreRoleId(storeId, role);
+ if (roleId == null)
+ return NotFound();
+
+ var roleData = await storeRepository.GetStoreRole(roleId, true);
if (roleData == null)
return NotFound();
@@ -142,7 +146,10 @@ public partial class UIStoresController
[FromServices] StoreRepository storeRepository,
string role)
{
- var roleId = new StoreRoleId(storeId, role);
+ var roleId = await storeRepository.ResolveStoreRoleId(storeId, role);
+ if (roleId == null)
+ return NotFound();
+
var roleData = await storeRepository.GetStoreRole(roleId, true);
if (roleData == null)
return NotFound();
diff --git a/BTCPayServer/Views/Shared/ListRoles.cshtml b/BTCPayServer/Views/Shared/ListRoles.cshtml
index 22926bc8c..847840022 100644
--- a/BTCPayServer/Views/Shared/ListRoles.cshtml
+++ b/BTCPayServer/Views/Shared/ListRoles.cshtml
@@ -118,8 +118,8 @@
{
Set as default
}
- Edit
- Remove
+ Edit
+ Remove