mirror of
https://github.com/bitwarden/server.git
synced 2025-04-25 14:52:21 -05:00
wip
This commit is contained in:
parent
eaa40e8239
commit
01a69176c5
@ -1,35 +0,0 @@
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@inject IHttpContextAccessor HttpContextAccessor
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<base href="/"/>
|
||||
<HeadOutlet/>
|
||||
</head>
|
||||
|
||||
<body class="h-full bg-gray-50">
|
||||
|
||||
<Router AppAssembly="@typeof(Program).Assembly">
|
||||
<Found Context="routeData">
|
||||
<!-- The 'Resource' property will be used in 'HasAppHandler' to obtain the 'app' route parameter -->
|
||||
<!-- If we implement new policies to protect resources, we should protect them with resource based uri and compare them with the user's claims. -->
|
||||
<AuthorizeRouteView RouteData="@routeData" Resource="@HttpContextAccessor.HttpContext">
|
||||
<!-- When visiting a page that requires authorization, but the user isn't authorized, redirect to the login page -->
|
||||
<NotAuthorized>
|
||||
</NotAuthorized>
|
||||
</AuthorizeRouteView>
|
||||
<FocusOnNavigate RouteData="@routeData" Selector="h1"/>
|
||||
</Found>
|
||||
</Router>
|
||||
<script src="_framework/blazor.web.js" autostart="false"></script>
|
||||
<script>
|
||||
Blazor.start({
|
||||
ssr: { disableDomPreservation: true }
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
92
src/Admin/AdminConsole/App.razor
Normal file
92
src/Admin/AdminConsole/App.razor
Normal file
@ -0,0 +1,92 @@
|
||||
@using Bit.Admin.Services
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@using Bit.Admin.Components.Navigation
|
||||
@inject IHttpContextAccessor HttpContextAccessor
|
||||
@inject SignInManager<IdentityUser> SignInManager
|
||||
@inject Core.Settings.GlobalSettings GlobalSettings
|
||||
@inject IAccessControlService AccessControlService
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<base href="/"/>
|
||||
<HeadOutlet/>
|
||||
<link href="assets/site.css" rel="stylesheet"/>
|
||||
<script src="assets/site.js"></script>
|
||||
</head>
|
||||
|
||||
<body class="h-full bg-gray-50">
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" asp-controller="Home" asp-action="Index">
|
||||
<i class="fa fa-lg fa-fw fa-shield"></i> Admin
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse"
|
||||
aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
@if (SignInManager.IsSignedIn(HttpContextAccessor.HttpContext!.User))
|
||||
{
|
||||
@foreach(var navItem in NavItems)
|
||||
{
|
||||
<NavItem Model="navItem"/>
|
||||
}
|
||||
}
|
||||
@if (GlobalSettings.SelfHosted)
|
||||
{
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://help.bitwarden.com/hosting/" target="_blank"
|
||||
rel="noreferrer">
|
||||
Docs
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
@if (SignInManager.IsSignedIn(HttpContextAccessor.HttpContext.User))
|
||||
{
|
||||
<form asp-controller="Login" asp-action="Logout" method="post">
|
||||
<button type="submit" class="btn btn-sm btn-secondary">Log Out</button>
|
||||
</form>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a class="btn btn-sm btn-secondary" asp-controller="Login" asp-action="Index">Log In</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main role="main" class="container">
|
||||
<Router AppAssembly="@typeof(Program).Assembly">
|
||||
<Found Context="routeData">
|
||||
<!-- The 'Resource' property will be used in 'HasAppHandler' to obtain the 'app' route parameter -->
|
||||
<!-- If we implement new policies to protect resources, we should protect them with resource based uri and compare them with the user's claims. -->
|
||||
<AuthorizeRouteView RouteData="@routeData" Resource="@HttpContextAccessor.HttpContext">
|
||||
<!-- When visiting a page that requires authorization, but the user isn't authorized, redirect to the login page -->
|
||||
<NotAuthorized>
|
||||
<!-- Empty -->
|
||||
</NotAuthorized>
|
||||
</AuthorizeRouteView>
|
||||
<FocusOnNavigate RouteData="@routeData" Selector="h1"/>
|
||||
</Found>
|
||||
</Router>
|
||||
</main>
|
||||
|
||||
<footer class="container mb-4">
|
||||
<hr/>
|
||||
© @DateTime.Now.Year, Bitwarden Inc.
|
||||
</footer>
|
||||
|
||||
<script src="_framework/blazor.web.js" autostart="false"></script>
|
||||
<script>
|
||||
Blazor.start({
|
||||
ssr: { disableDomPreservation: true }
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
84
src/Admin/AdminConsole/App.razor.cs
Normal file
84
src/Admin/AdminConsole/App.razor.cs
Normal file
@ -0,0 +1,84 @@
|
||||
using Bit.Admin.Enums;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Bit.Admin.AdminConsole;
|
||||
|
||||
public partial class App : ComponentBase
|
||||
{
|
||||
public HashSet<NavItem.ViewModel> NavItems { get; private set; }
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
var canViewUsers = AccessControlService.UserHasPermission(Permission.User_List_View);
|
||||
var canViewOrgs = AccessControlService.UserHasPermission(Permission.Org_List_View);
|
||||
var canViewProviders = AccessControlService.UserHasPermission(Permission.Provider_List_View);
|
||||
var canChargeBraintree = AccessControlService.UserHasPermission(Permission.Tools_ChargeBrainTreeCustomer);
|
||||
var canCreateTransaction = AccessControlService.UserHasPermission(Permission.Tools_CreateEditTransaction);
|
||||
var canPromoteAdmin = AccessControlService.UserHasPermission(Permission.Tools_PromoteAdmin);
|
||||
var canGenerateLicense = AccessControlService.UserHasPermission(Permission.Tools_GenerateLicenseFile);
|
||||
var canManageTaxRates = AccessControlService.UserHasPermission(Permission.Tools_ManageTaxRates);
|
||||
var canManageStripeSubscriptions =
|
||||
AccessControlService.UserHasPermission(Permission.Tools_ManageStripeSubscriptions);
|
||||
var canProcessStripeEvents = AccessControlService.UserHasPermission(Permission.Tools_ProcessStripeEvents);
|
||||
var canMigrateProviders = AccessControlService.UserHasPermission(Permission.Tools_MigrateProviders);
|
||||
|
||||
var canViewTools = canChargeBraintree || canCreateTransaction || canPromoteAdmin ||
|
||||
canGenerateLicense || canManageTaxRates || canManageStripeSubscriptions;
|
||||
|
||||
NavItems =
|
||||
[
|
||||
new() { Label = "Users", Link = "/users", Show = canViewUsers },
|
||||
|
||||
new() { Label = "Organizations", Link = "/organizations", Show = canViewOrgs },
|
||||
new() { Label = "Providers", Link = "/providers", Show = canViewProviders && !GlobalSettings.SelfHosted },
|
||||
new()
|
||||
{
|
||||
Label = "Tools",
|
||||
Link = "/tools",
|
||||
Show = canViewTools && !GlobalSettings.SelfHosted,
|
||||
DropDownItems =
|
||||
[
|
||||
new()
|
||||
{
|
||||
Label = "Charge Braintree Customer",
|
||||
Link = "/tools/chargebraintree",
|
||||
Show = canChargeBraintree
|
||||
},
|
||||
|
||||
new()
|
||||
{
|
||||
Label = "Create/Edit Transaction",
|
||||
Link = "/tools/createtransaction",
|
||||
Show = canCreateTransaction
|
||||
},
|
||||
|
||||
new() { Label = "Promote Admin", Link = "/tools/promoteadmin", Show = canPromoteAdmin },
|
||||
new()
|
||||
{
|
||||
Label = "Generate License File",
|
||||
Link = "/tools/generatelicense",
|
||||
Show = canGenerateLicense
|
||||
},
|
||||
|
||||
new() { Label = "Manage Tax Rates", Link = "/tools/taxrate", Show = canManageTaxRates },
|
||||
|
||||
new()
|
||||
{
|
||||
Label = "Manage Stripe Subscriptions",
|
||||
Link = "/tools/stripesubscriptions",
|
||||
Show = canManageStripeSubscriptions
|
||||
},
|
||||
|
||||
new()
|
||||
{
|
||||
Label = "Process Stripe Events",
|
||||
Link = "/process-stripe-events",
|
||||
Show = canProcessStripeEvents
|
||||
},
|
||||
|
||||
new() { Label = "Migrate Providers", Link = "/tools/migrateproviders", Show = canMigrateProviders }
|
||||
]
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
@page "/organizations2"
|
||||
@using Bit.Core.Repositories
|
||||
@using Bit.Core.Settings
|
||||
@using Bit.Infrastructure.EntityFramework.AdminConsole.Models
|
||||
|
||||
@inject IGlobalSettings GlobalSettings
|
||||
@inject IOrganizationRepository OrganizationRepository
|
||||
|
||||
<!-- You cannot set the title part of a layout due to the rendering order. Or you have to use JavaScript, which is not
|
||||
ideal. -->
|
||||
<BitPage Title="Organizations">
|
||||
<EditForm class="form-inline mb-2" FormName="@SearchFormName" Model="SearchForm" OnSubmit="OnSearchAsync">
|
||||
<DataAnnotationsValidator/>
|
||||
<ValidationSummary/>
|
||||
|
||||
<label class="sr-only" for="name-filter">Name</label>
|
||||
<InputText @bind-Value="SearchForm.Name" class="form-control mb-2 mr-2" id="name-filter" placeholder="Name"/>
|
||||
<label class="sr-only" for="email-filter">User email</label>
|
||||
<InputText @bind-Value="SearchForm.Email" class="form-control mb-2 mr-2" id="email-filter" placeholder="User email"/>
|
||||
|
||||
@if (!Model.SelfHosted)
|
||||
{
|
||||
<label class="sr-only" asp-for="Paid">Customer</label>
|
||||
<InputSelect @bind-Value="SearchForm.Paid" class="form-control mb-2 mr-2">
|
||||
<option value="">-- Customer --</option>
|
||||
<option value="true">Paid</option>
|
||||
<option value="false">Freeloader</option>
|
||||
</InputSelect>
|
||||
}
|
||||
<button type="submit" class="btn btn-primary mb-2" title="Search"><i class="fa fa-search"></i> Search</button>
|
||||
</EditForm>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th style="width: 190px;">Plan</th>
|
||||
<th style="width: 80px;">Seats</th>
|
||||
<th style="width: 150px;">Created</th>
|
||||
<th style="width: 170px; min-width: 170px;">Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if (Model.Items is { Count: > 0 })
|
||||
{
|
||||
@foreach (var organization in Model.Items)
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
<a href="@($"/organizations/edit/{organization.Id}")">@organization.DisplayName()</a>
|
||||
</td>
|
||||
<td>
|
||||
@organization.Plan
|
||||
</td>
|
||||
<td>
|
||||
@organization.Seats
|
||||
</td>
|
||||
<td>
|
||||
<span title="@organization.CreationDate.ToString()">
|
||||
@organization.CreationDate.ToShortDateString()
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
@if (!GlobalSettings.SelfHosted)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(organization.GatewaySubscriptionId))
|
||||
{
|
||||
<i class="fa fa-usd fa-lg fa-fw" title="Paid"></i>
|
||||
}
|
||||
else
|
||||
{
|
||||
<i class="fa fa-smile-o fa-lg fa-fw text-muted" title="Freeloader"></i>
|
||||
}
|
||||
}
|
||||
@if (organization.MaxStorageGb is > 1)
|
||||
{
|
||||
<i class="fa fa-plus-square fa-lg fa-fw"
|
||||
title="Additional Storage, @(organization.MaxStorageGb - 1) GB">
|
||||
</i>
|
||||
}
|
||||
else
|
||||
{
|
||||
<i class="fa fa-plus-square-o fa-lg fa-fw text-muted"
|
||||
title="No Additional Storage">
|
||||
</i>
|
||||
}
|
||||
@if (organization.Enabled)
|
||||
{
|
||||
<i class="fa fa-check-circle fa-lg fa-fw"
|
||||
title="Enabled, expires @(organization.ExpirationDate?.ToShortDateString() ?? "-")">
|
||||
</i>
|
||||
}
|
||||
else
|
||||
{
|
||||
<i class="fa fa-times-circle-o fa-lg fa-fw text-muted" title="Disabled"></i>
|
||||
}
|
||||
@if (organization.TwoFactorIsEnabled())
|
||||
{
|
||||
<i class="fa fa-lock fa-lg fa-fw" title="2FA Enabled"></i>
|
||||
}
|
||||
else
|
||||
{
|
||||
<i class="fa fa-unlock fa-lg fa-fw text-muted" title="2FA Not Enabled"></i>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<tr>
|
||||
<td colspan="5">No results to list.</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<EditForm FormName="PaginationForm" Model="SearchForm" OnSubmit="OnSearchAsync">
|
||||
<nav>
|
||||
<ul class="pagination">
|
||||
@if (Model.Items != null && Model.PreviousPage.HasValue)
|
||||
{
|
||||
<li class="page-item">
|
||||
<a class="page-link" asp-action="Index" asp-route-page="@Model.PreviousPage.Value"
|
||||
asp-route-count="@Model.Count" asp-route-userEmail="@SearchForm.Email"
|
||||
asp-route-name="@SearchForm.Name" asp-route-paid="@SearchForm.Paid">
|
||||
Previous
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
else
|
||||
{
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" tabindex="-1">Previous</a>
|
||||
</li>
|
||||
}
|
||||
@if (Model.Items != null && Model.NextPage.HasValue)
|
||||
{
|
||||
<li class="page-item">
|
||||
<a class="page-link" asp-action="Index" asp-route-page="@Model.NextPage.Value"
|
||||
asp-route-count="@Model.Count" asp-route-userEmail="@SearchForm.Email"
|
||||
asp-route-name="@SearchForm.Name" asp-route-paid="@SearchForm.Paid">
|
||||
Next
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
else
|
||||
{
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" tabindex="-1">Next</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</nav>
|
||||
</EditForm>
|
||||
</BitPage>
|
@ -0,0 +1,92 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Net;
|
||||
using Bit.Admin.Models;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Bit.Admin.AdminConsole.Components.Pages.Organizations;
|
||||
|
||||
public partial class ListOrganizationsPage : ComponentBase
|
||||
{
|
||||
public const string SearchFormName = "search-form";
|
||||
|
||||
[SupplyParameterFromForm(FormName = SearchFormName)]
|
||||
public SearchFormModel? SearchForm { get; set; }
|
||||
|
||||
public ViewModel Model { get; } = new();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
SearchForm ??= new SearchFormModel();
|
||||
Model.SelfHosted = GlobalSettings.SelfHosted;
|
||||
Model.Action = GlobalSettings.SelfHosted ? "View" : "Edit";
|
||||
}
|
||||
|
||||
private async Task OnSearchAsync()
|
||||
{
|
||||
if (SearchForm!.Page < 1)
|
||||
{
|
||||
SearchForm.Page = 1;
|
||||
}
|
||||
|
||||
if (SearchForm.Count < 1)
|
||||
{
|
||||
SearchForm.Count = 1;
|
||||
}
|
||||
|
||||
var encodedName = WebUtility.HtmlEncode(SearchForm.Name);
|
||||
var skip = (SearchForm.Page - 1) * SearchForm.Count;
|
||||
Model.Items = (List<Organization>)await OrganizationRepository.SearchAsync(
|
||||
encodedName,
|
||||
SearchForm.Email,
|
||||
SearchForm.Paid, skip, SearchForm.Count);
|
||||
|
||||
Model.Page = SearchForm.Page;
|
||||
Model.Count = SearchForm.Count;
|
||||
}
|
||||
|
||||
public class SearchFormModel
|
||||
{
|
||||
private string? _name;
|
||||
|
||||
public string? Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(_name) ? null : _name;
|
||||
}
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
}
|
||||
}
|
||||
|
||||
private string? _email;
|
||||
|
||||
[EmailAddress]
|
||||
public string? Email
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(_email) ? null : _email;
|
||||
}
|
||||
set
|
||||
{
|
||||
_email = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool? Paid { get; set; }
|
||||
|
||||
public int Page { get; set; } = 1;
|
||||
|
||||
public int Count { get; set; } = 25;
|
||||
}
|
||||
|
||||
public class ViewModel : PagedModel<Organization>
|
||||
{
|
||||
public string Action { get; set; }
|
||||
public bool SelfHosted { get; set; }
|
||||
}
|
||||
}
|
||||
|
3
src/Admin/AdminConsole/Components/_Imports.razor
Normal file
3
src/Admin/AdminConsole/Components/_Imports.razor
Normal file
@ -0,0 +1,3 @@
|
||||
@attribute [Authorize]
|
||||
|
||||
@using Bit.Admin.Components
|
4
src/Admin/Components/BitPage.razor
Normal file
4
src/Admin/Components/BitPage.razor
Normal file
@ -0,0 +1,4 @@
|
||||
<PageTitle>@Title</PageTitle>
|
||||
|
||||
<h1>@Title</h1>
|
||||
@ChildContent
|
16
src/Admin/Components/BitPage.razor.cs
Normal file
16
src/Admin/Components/BitPage.razor.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Bit.Admin.Components;
|
||||
|
||||
public partial class BitPage : ComponentBase
|
||||
{
|
||||
[Parameter]
|
||||
public required string Title { get; set; }
|
||||
|
||||
[Parameter] public bool HideTitle { get; set; } = false;
|
||||
|
||||
[Parameter]
|
||||
public required RenderFragment ChildContent { get; set; }
|
||||
|
||||
private string? TitleClass => HideTitle ? "sr-only" : null;
|
||||
}
|
20
src/Admin/Components/Navigation/NavDropDownItem.razor
Normal file
20
src/Admin/Components/Navigation/NavDropDownItem.razor
Normal file
@ -0,0 +1,20 @@
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.Azure.Cosmos.Core.Collections
|
||||
|
||||
<NavLink class="dropdown-item" href="@Model.Link">
|
||||
@Model.Label
|
||||
</NavLink>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public required ViewModel Model { get; set; }
|
||||
|
||||
public class ViewModel
|
||||
{
|
||||
public required string Label { get; set; }
|
||||
|
||||
public required string Link { get; set; }
|
||||
|
||||
public bool Show { get; set; } = true;
|
||||
}
|
||||
}
|
61
src/Admin/Components/Navigation/NavItem.razor
Normal file
61
src/Admin/Components/Navigation/NavItem.razor
Normal file
@ -0,0 +1,61 @@
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<li class="@Class">
|
||||
@if (Model.DropDownItems is { Count: > 0 })
|
||||
{
|
||||
<NavLink class="nav-link dropdown-toggle" href="@Model.Link" id="@Model.LinkId" role="button"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
Tools
|
||||
</NavLink>
|
||||
<div class="dropdown-menu" aria-labelledby="@Model.LinkId">
|
||||
@foreach (var item in Model.DropDownItems)
|
||||
{
|
||||
<NavDropDownItem Model="item"/>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<NavLink class="nav-link" href="@Model.Link">
|
||||
@Model.Label
|
||||
</NavLink>
|
||||
}
|
||||
</li>
|
||||
|
||||
@code {
|
||||
public string Class { get; private set; }
|
||||
|
||||
[Parameter]
|
||||
public ViewModel Model { get; set; }
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
var isActive = NavigationManager.Uri.ToLowerInvariant().Contains(Model.Link.ToLowerInvariant());
|
||||
var classes = new List<string>();
|
||||
if (isActive)
|
||||
{
|
||||
classes.Add("active");
|
||||
}
|
||||
classes.Add("nav-item");
|
||||
if (Model.DropDownItems is { Count: > 0 })
|
||||
{
|
||||
classes.Add("dropdown");
|
||||
}
|
||||
Class = string.Join(" ", classes);
|
||||
}
|
||||
|
||||
public class ViewModel
|
||||
{
|
||||
public required string Link { get; set; }
|
||||
|
||||
public string LinkId { get; set; }
|
||||
|
||||
public required string Label { get; set; }
|
||||
|
||||
public HashSet<NavDropDownItem.ViewModel>? DropDownItems { get; set; }
|
||||
|
||||
public bool Show { get; set; } = true;
|
||||
}
|
||||
}
|
1
src/Admin/Components/_Imports.razor
Normal file
1
src/Admin/Components/_Imports.razor
Normal file
@ -0,0 +1 @@
|
||||
@using Microsoft.AspNetCore.Components.Web
|
@ -170,7 +170,7 @@ public class Startup
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapDefaultControllerRoute();
|
||||
endpoints.MapRazorComponents<AdminConsoleRootApp>();
|
||||
endpoints.MapRazorComponents<App>();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user