mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 06:24:24 +01:00
Apps become plugins
Unified navigation for apps that are now plugins. Part of #4744.
This commit is contained in:
@@ -77,8 +77,7 @@ namespace BTCPayServer.Tests
|
|||||||
s.GenerateWallet(isHotWallet: true);
|
s.GenerateWallet(isHotWallet: true);
|
||||||
|
|
||||||
// Point Of Sale
|
// Point Of Sale
|
||||||
s.Driver.FindElement(By.Id("StoreNav-CreateApp")).Click();
|
s.Driver.FindElement(By.Id("StoreNav-CreatePointOfSale")).Click();
|
||||||
new SelectElement(s.Driver.FindElement(By.Id("SelectedAppType"))).SelectByValue("PointOfSale");
|
|
||||||
s.Driver.FindElement(By.Id("AppName")).SendKeys(Guid.NewGuid().ToString());
|
s.Driver.FindElement(By.Id("AppName")).SendKeys(Guid.NewGuid().ToString());
|
||||||
s.Driver.FindElement(By.Id("Create")).Click();
|
s.Driver.FindElement(By.Id("Create")).Click();
|
||||||
Assert.Contains("App successfully created", s.FindAlertMessage().Text);
|
Assert.Contains("App successfully created", s.FindAlertMessage().Text);
|
||||||
@@ -939,9 +938,8 @@ namespace BTCPayServer.Tests
|
|||||||
await s.StartAsync();
|
await s.StartAsync();
|
||||||
var userId = s.RegisterNewUser(true);
|
var userId = s.RegisterNewUser(true);
|
||||||
s.CreateNewStore();
|
s.CreateNewStore();
|
||||||
s.Driver.FindElement(By.Id("StoreNav-CreateApp")).Click();
|
s.Driver.FindElement(By.Id("StoreNav-CreatePointOfSale")).Click();
|
||||||
s.Driver.FindElement(By.Name("AppName")).SendKeys("PoS" + Guid.NewGuid());
|
s.Driver.FindElement(By.Name("AppName")).SendKeys("PoS" + Guid.NewGuid());
|
||||||
s.Driver.FindElement(By.Id("SelectedAppType")).SendKeys("Point of Sale");
|
|
||||||
s.Driver.FindElement(By.Id("Create")).Click();
|
s.Driver.FindElement(By.Id("Create")).Click();
|
||||||
Assert.Contains("App successfully created", s.FindAlertMessage().Text);
|
Assert.Contains("App successfully created", s.FindAlertMessage().Text);
|
||||||
|
|
||||||
@@ -1027,9 +1025,8 @@ namespace BTCPayServer.Tests
|
|||||||
s.CreateNewStore();
|
s.CreateNewStore();
|
||||||
s.AddDerivationScheme();
|
s.AddDerivationScheme();
|
||||||
|
|
||||||
s.Driver.FindElement(By.Id("StoreNav-CreateApp")).Click();
|
s.Driver.FindElement(By.Id("StoreNav-CreateCrowdfund")).Click();
|
||||||
s.Driver.FindElement(By.Name("AppName")).SendKeys("CF" + Guid.NewGuid());
|
s.Driver.FindElement(By.Name("AppName")).SendKeys("CF" + Guid.NewGuid());
|
||||||
s.Driver.FindElement(By.Id("SelectedAppType")).SendKeys("Crowdfund");
|
|
||||||
s.Driver.FindElement(By.Id("Create")).Click();
|
s.Driver.FindElement(By.Id("Create")).Click();
|
||||||
Assert.Contains("App successfully created", s.FindAlertMessage().Text);
|
Assert.Contains("App successfully created", s.FindAlertMessage().Text);
|
||||||
|
|
||||||
@@ -2006,9 +2003,7 @@ namespace BTCPayServer.Tests
|
|||||||
s.AddLightningNode(LightningConnectionType.CLightning, false);
|
s.AddLightningNode(LightningConnectionType.CLightning, false);
|
||||||
s.GoToLightningSettings();
|
s.GoToLightningSettings();
|
||||||
s.Driver.SetCheckbox(By.Id("LNURLEnabled"), true);
|
s.Driver.SetCheckbox(By.Id("LNURLEnabled"), true);
|
||||||
s.Driver.FindElement(By.Id("StoreNav-CreateApp")).Click();
|
s.Driver.FindElement(By.Id("StoreNav-CreatePointOfSale")).Click();
|
||||||
s.Driver.FindElement(By.Id("SelectedAppType")).Click();
|
|
||||||
s.Driver.FindElement(By.CssSelector("option[value='PointOfSale']")).Click();
|
|
||||||
s.Driver.FindElement(By.Id("AppName")).SendKeys(Guid.NewGuid().ToString());
|
s.Driver.FindElement(By.Id("AppName")).SendKeys(Guid.NewGuid().ToString());
|
||||||
s.Driver.FindElement(By.Id("Create")).Click();
|
s.Driver.FindElement(By.Id("Create")).Click();
|
||||||
TestUtils.Eventually(() => Assert.Contains("App successfully created", s.FindAlertMessage().Text));
|
TestUtils.Eventually(() => Assert.Contains("App successfully created", s.FindAlertMessage().Text));
|
||||||
|
|||||||
@@ -155,30 +155,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="accordion-item" permission="@Policies.CanModifyStoreSettings">
|
|
||||||
<header class="accordion-header" id="Nav-Apps-Header">
|
|
||||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#Nav-Apps" aria-expanded="true" aria-controls="Nav-Apps">
|
|
||||||
Apps
|
|
||||||
<vc:icon symbol="caret-down"/>
|
|
||||||
</button>
|
|
||||||
</header>
|
|
||||||
<div id="Nav-Apps" class="accordion-collapse collapse show" aria-labelledby="Nav-Apps-Header">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<ul class="navbar-nav">
|
|
||||||
@foreach (var app in Model.Apps)
|
|
||||||
{
|
|
||||||
<vc:ui-extension-point location="apps-nav" model="@app"/>
|
|
||||||
}
|
|
||||||
<li class="nav-item">
|
|
||||||
<a asp-area="" asp-controller="UIApps" asp-action="CreateApp" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.IsActivePage(AppsNavPages.Create)" id="StoreNav-CreateApp">
|
|
||||||
<vc:icon symbol="new"/>
|
|
||||||
<span>New App</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
<div class="accordion-item">
|
<div class="accordion-item">
|
||||||
<header class="accordion-header" id="Nav-Plugins-Header">
|
<header class="accordion-header" id="Nav-Plugins-Header">
|
||||||
@@ -195,9 +171,11 @@
|
|||||||
{
|
{
|
||||||
<vc:ui-extension-point location="store-integrations-nav" model="@Model"/>
|
<vc:ui-extension-point location="store-integrations-nav" model="@Model"/>
|
||||||
}
|
}
|
||||||
|
</ul>
|
||||||
|
<ul class="navbar-nav">
|
||||||
<li class="nav-item" permission="@Policies.CanModifyServerSettings">
|
<li class="nav-item" permission="@Policies.CanModifyServerSettings">
|
||||||
<a asp-area="" asp-controller="UIServer" asp-action="ListPlugins" class="nav-link @ViewData.IsActivePage(ServerNavPages.Plugins)" id="Nav-ManagePlugins">
|
<a asp-area="" asp-controller="UIServer" asp-action="ListPlugins" class="nav-link @ViewData.IsActivePage(ServerNavPages.Plugins)" id="Nav-ManagePlugins">
|
||||||
<vc:icon symbol="new"/>
|
<vc:icon symbol="plugin"/>
|
||||||
<span>Manage Plugins</span>
|
<span>Manage Plugins</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -111,22 +111,29 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||||
[HttpGet("/stores/{storeId}/apps/create")]
|
[HttpGet("/stores/{storeId}/apps/create/{appType?}")]
|
||||||
public IActionResult CreateApp(string storeId, string appType = null)
|
public IActionResult CreateApp(string storeId, string appType = null)
|
||||||
{
|
{
|
||||||
var vm = new CreateAppViewModel (_appService){StoreId = GetCurrentStore().Id, SelectedAppType = appType};
|
var vm = new CreateAppViewModel(_appService)
|
||||||
|
{
|
||||||
|
StoreId = storeId,
|
||||||
|
AppType = appType,
|
||||||
|
SelectedAppType = appType
|
||||||
|
};
|
||||||
return View(vm);
|
return View(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||||
[HttpPost("/stores/{storeId}/apps/create")]
|
[HttpPost("/stores/{storeId}/apps/create/{appType?}")]
|
||||||
public async Task<IActionResult> CreateApp(string storeId, CreateAppViewModel vm)
|
public async Task<IActionResult> CreateApp(string storeId, CreateAppViewModel vm)
|
||||||
{
|
{
|
||||||
var store = GetCurrentStore();
|
var store = GetCurrentStore();
|
||||||
vm.StoreId = store.Id;
|
vm.StoreId = store.Id;
|
||||||
var type = _appService.GetAppType(vm.SelectedAppType);
|
var type = _appService.GetAppType(vm.AppType ?? vm.SelectedAppType);
|
||||||
if (type is null)
|
if (type is null)
|
||||||
|
{
|
||||||
ModelState.AddModelError(nameof(vm.SelectedAppType), "Invalid App Type");
|
ModelState.AddModelError(nameof(vm.SelectedAppType), "Invalid App Type");
|
||||||
|
}
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
{
|
{
|
||||||
@@ -137,7 +144,7 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
StoreDataId = store.Id,
|
StoreDataId = store.Id,
|
||||||
Name = vm.AppName,
|
Name = vm.AppName,
|
||||||
AppType = vm.SelectedAppType
|
AppType = type!.Type
|
||||||
};
|
};
|
||||||
|
|
||||||
var defaultCurrency = await GetStoreDefaultCurrentIfEmpty(appData.StoreDataId, null);
|
var defaultCurrency = await GetStoreDefaultCurrentIfEmpty(appData.StoreDataId, null);
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ namespace BTCPayServer.Models.AppViewModels
|
|||||||
public string SelectedAppType { get; set; }
|
public string SelectedAppType { get; set; }
|
||||||
|
|
||||||
public SelectList AppTypes { get; set; }
|
public SelectList AppTypes { get; set; }
|
||||||
|
public string AppType { get; set; }
|
||||||
|
|
||||||
private void SetApps(AppService appService)
|
private void SetApps(AppService appService)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace BTCPayServer.Plugins.Crowdfund
|
|||||||
|
|
||||||
public override void Execute(IServiceCollection services)
|
public override void Execute(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddSingleton<IUIExtension>(new UIExtension("Crowdfund/NavExtension", "apps-nav"));
|
services.AddSingleton<IUIExtension>(new UIExtension("Crowdfund/NavExtension", "header-nav"));
|
||||||
services.AddSingleton<CrowdfundAppType>();
|
services.AddSingleton<CrowdfundAppType>();
|
||||||
services.AddSingleton<AppBaseType, CrowdfundAppType>();
|
services.AddSingleton<AppBaseType, CrowdfundAppType>();
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace BTCPayServer.Plugins.PointOfSale
|
|||||||
|
|
||||||
public override void Execute(IServiceCollection services)
|
public override void Execute(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddSingleton<IUIExtension>(new UIExtension("PointOfSale/NavExtension", "apps-nav"));
|
services.AddSingleton<IUIExtension>(new UIExtension("PointOfSale/NavExtension", "header-nav"));
|
||||||
services.AddSingleton<AppBaseType, PointOfSaleAppType>();
|
services.AddSingleton<AppBaseType, PointOfSaleAppType>();
|
||||||
base.Execute(services);
|
base.Execute(services);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,16 +4,28 @@
|
|||||||
@using BTCPayServer.Abstractions.Extensions
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
@using BTCPayServer.Abstractions.TagHelpers
|
@using BTCPayServer.Abstractions.TagHelpers
|
||||||
@using BTCPayServer.Plugins.Crowdfund
|
@using BTCPayServer.Plugins.Crowdfund
|
||||||
@model BTCPayServer.Components.MainNav.StoreApp
|
@using BTCPayServer.Services.Apps
|
||||||
|
@inject AppService AppService;
|
||||||
|
@model BTCPayServer.Components.MainNav.MainNavViewModel
|
||||||
|
@{
|
||||||
|
var store = Context.GetStoreData();
|
||||||
|
}
|
||||||
|
|
||||||
@{ var store = Context.GetStoreData(); }
|
@if (store != null)
|
||||||
|
|
||||||
@if (store != null && Model.AppType == CrowdfundAppType.AppType)
|
|
||||||
{
|
{
|
||||||
|
var appType = AppService.GetAppType(CrowdfundAppType.AppType)!;
|
||||||
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
||||||
<a asp-area="" asp-controller="UICrowdfund" asp-action="UpdateCrowdfund" asp-route-appId="@Model.Id" class="nav-link @ViewData.IsActivePage(AppsNavPages.Update, Model.Id)" id="@($"StoreNav-App-{Model.Id}")">
|
<a asp-area="" asp-controller="UIApps" asp-action="CreateApp" asp-route-storeId="@store.Id" asp-route-appType="@appType.Type" class="nav-link @ViewData.IsActivePage(AppsNavPages.Create, appType.Type)" id="@($"StoreNav-Create{appType.Type}")">
|
||||||
<vc:icon symbol="@Model.AppType.ToLower()"/>
|
<vc:icon symbol="crowdfund" />
|
||||||
<span>@Model.AppName</span>
|
<span>@appType.Description</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@foreach (var app in Model.Apps.Where(app => app.AppType == appType.Type))
|
||||||
|
{
|
||||||
|
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings">
|
||||||
|
<a asp-area="" asp-controller="UICrowdfund" asp-action="UpdateCrowdfund" asp-route-appId="@app.Id" class="nav-link @ViewData.IsActivePage(AppsNavPages.Update, app.Id)" id="@($"StoreNav-App-{app.Id}")">
|
||||||
|
<span>@app.AppName</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,17 +4,28 @@
|
|||||||
@using BTCPayServer.Abstractions.Extensions
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
@using BTCPayServer.Abstractions.TagHelpers
|
@using BTCPayServer.Abstractions.TagHelpers
|
||||||
@using BTCPayServer.Plugins.PointOfSale
|
@using BTCPayServer.Plugins.PointOfSale
|
||||||
@model BTCPayServer.Components.MainNav.StoreApp
|
@using BTCPayServer.Services.Apps
|
||||||
|
@inject AppService AppService;
|
||||||
@{ var store = Context.GetStoreData(); }
|
@model BTCPayServer.Components.MainNav.MainNavViewModel
|
||||||
|
@{
|
||||||
@if (store != null && Model.AppType == PointOfSaleAppType.AppType)
|
var store = Context.GetStoreData();
|
||||||
{
|
|
||||||
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
|
||||||
<a asp-area="" asp-controller="UIPointOfSale" asp-action="UpdatePointOfSale" asp-route-appId="@Model.Id" class="nav-link @ViewData.IsActivePage(AppsNavPages.Update, Model.Id)" id="@($"StoreNav-App-{Model.Id}")">
|
|
||||||
<vc:icon symbol="@Model.AppType.ToLower()"/>
|
|
||||||
<span>@Model.AppName</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@if (store != null)
|
||||||
|
{
|
||||||
|
var appType = AppService.GetAppType(PointOfSaleAppType.AppType)!;
|
||||||
|
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
||||||
|
<a asp-area="" asp-controller="UIApps" asp-action="CreateApp" asp-route-storeId="@store.Id" asp-route-appType="@appType.Type" class="nav-link @ViewData.IsActivePage(AppsNavPages.Create, appType.Type)" id="@($"StoreNav-Create{appType.Type}")">
|
||||||
|
<vc:icon symbol="pointofsale" />
|
||||||
|
<span>@appType.Description</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
@foreach (var app in Model.Apps.Where(app => app.AppType == appType.Type))
|
||||||
|
{
|
||||||
|
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings">
|
||||||
|
<a asp-area="" asp-controller="UIPointOfSale" asp-action="UpdatePointOfSale" asp-route-appId="@app.Id" class="nav-link @ViewData.IsActivePage(AppsNavPages.Update, app.Id)" id="@($"StoreNav-App-{app.Id}")">
|
||||||
|
<span>@app.AppName</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@model CreateAppViewModel
|
@model CreateAppViewModel
|
||||||
@{
|
@{
|
||||||
ViewData.SetActivePage(AppsNavPages.Create, "Create a new app");
|
ViewData.SetActivePage(AppsNavPages.Create, $"Create a new {Model.AppType ?? "app"}", Model.AppType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section PageFootContent {
|
@section PageFootContent {
|
||||||
@@ -13,12 +13,15 @@
|
|||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xl-8 col-xxl-constrain">
|
<div class="col-xl-8 col-xxl-constrain">
|
||||||
<form asp-action="CreateApp">
|
<form asp-action="CreateApp" asp-route-appType="@Model.AppType">
|
||||||
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
|
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
|
||||||
|
@if (string.IsNullOrEmpty(Model.AppType))
|
||||||
|
{
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="SelectedAppType" class="form-label" data-required></label>
|
<label asp-for="SelectedAppType" class="form-label" data-required></label>
|
||||||
<select asp-for="SelectedAppType" asp-items="Model.AppTypes" class="form-select"></select>
|
<select asp-for="SelectedAppType" asp-items="Model.AppTypes" class="form-select"></select>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="AppName" class="form-label" data-required></label>
|
<label asp-for="AppName" class="form-label" data-required></label>
|
||||||
<input asp-for="AppName" class="form-control" required />
|
<input asp-for="AppName" class="form-control" required />
|
||||||
|
|||||||
@@ -80,6 +80,10 @@
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#mainNav .navbar-nav > li.nav-item-sub {
|
||||||
|
padding-left:calc(1.5rem + var(--btcpay-space-xs))
|
||||||
|
}
|
||||||
|
|
||||||
#mainNav .navbar-nav > li.nav-item .nav-link span {
|
#mainNav .navbar-nav > li.nav-item .nav-link span {
|
||||||
max-width: 200px;
|
max-width: 200px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|||||||
Reference in New Issue
Block a user