1
0

Compare commits

...

11 Commits

Author SHA1 Message Date
7159c8ffed Replace foreach loop with Virtualize component.
Improves performance greatly when lots of li elements are to be created. Note that every li should have the same height in pixels in order for the Virtualize component to work properly.
2025-03-26 00:09:03 +01:00
ea04b947e8 Add key to li elements for servers.
This improves performance. If a new server was to be added interactively, then ALL li elements would update. With this key, only the new li element will be added.
2025-03-25 23:57:26 +01:00
b02d6d2bb9 Apply two-way data binding for search bar. 2025-03-25 23:43:06 +01:00
1ebbced64b Move button to add server under search bar. 2025-03-25 23:42:42 +01:00
c8cd3d07b5 Add search bar to filter server names. 2025-03-25 23:24:35 +01:00
1577933bb4 Create active view for city cards. 2025-03-25 22:41:32 +01:00
a22d8d7ffd Remove loose server component from servers page. 2025-03-25 22:41:09 +01:00
838fc29b51 Filter servers by city by adding functionality to buttons under city cards. 2025-03-25 21:43:49 +01:00
1d7bb19c40 Apply global server side rendering, but exclude certain routable components. (.NET 9 feature) 2025-03-25 15:01:37 +01:00
b23f7bac27 Add additional logging information. 2025-03-25 15:00:28 +01:00
1110a709fb Migrate project from .NET 8.0 to target .NET 9.0 instead. 2025-03-25 14:23:56 +01:00
7 changed files with 63 additions and 13 deletions

View File

@ -9,13 +9,23 @@
<link rel="stylesheet" href="app.css" /> <link rel="stylesheet" href="app.css" />
<link rel="stylesheet" href="ServerManagement.styles.css" /> <link rel="stylesheet" href="ServerManagement.styles.css" />
<link rel="icon" type="image/png" href="favicon.png" /> <link rel="icon" type="image/png" href="favicon.png" />
<HeadOutlet /> <HeadOutlet @rendermode="@PageRenderMode"/>
</head> </head>
<body> <body>
@* Note that @rendermode="InteractiveServer" can be used here on Routes to make it global. But this is not recommended by Microsoft. See: https://learn.microsoft.com/en-us/aspnet/core/blazor/components/render-modes?view=aspnetcore-9.0 *@ @* Note that @rendermode="InteractiveServer" can be used here on Routes to make it global. But this is not recommended by Microsoft. See: https://learn.microsoft.com/en-us/aspnet/core/blazor/components/render-modes?view=aspnetcore-9.0 *@
<Routes/> <Routes @rendermode="@PageRenderMode"/>
<script src="_framework/blazor.web.js"></script> <script src="_framework/blazor.web.js"></script>
</body> </body>
</html> </html>
@code {
@* Use for .NET 9, and make interactivity global in Routes and HeadOutlet components in App.razor file. *@
@* See: https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-9.0?view=aspnetcore-9.0#add-static-server-side-rendering-ssr-pages-to-a-globally-interactive-blazor-web-app *@
[CascadingParameter]
private HttpContext HttpContext { get; set; } = default!;
private IComponentRenderMode? PageRenderMode
=> HttpContext.AcceptsInteractiveRouting() ? InteractiveServer : null;
}

View File

@ -1,6 +1,8 @@
@page "/servers/add" @page "/servers/add"
@using System.ComponentModel.DataAnnotations @using System.ComponentModel.DataAnnotations
@attribute [ExcludeFromInteractiveRouting]
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
<h3>Add server</h3> <h3>Add server</h3>

View File

@ -1,6 +1,8 @@
@page "/servers/{id:int}" @page "/servers/{id:int}"
@* Route constraints: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-9.0#route-constraints *@ @* Route constraints: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-9.0#route-constraints *@
@attribute [ExcludeFromInteractiveRouting]
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
<h3>Edit server</h3> <h3>Edit server</h3>

View File

@ -13,10 +13,10 @@
{ {
<div class="col"> <div class="col">
<div class="card"> <div class="card @((city == selectedCity) ? "border-primary" : "")">
<img src="@($"/images/{city}.png")" class="card-img-top" alt="@city")"> <img src=@($"/images/{@city}.png") class="card-img-top" alt="@city">
<div class="card-body"> <div class="card-body @((city == selectedCity) ? "active" : "")">
<button class="btn btn-primary">@city</button> <button class="btn btn-primary" @onclick="@(() => { SelectCity(city); })">@city</button>
</div> </div>
</div> </div>
</div> </div>
@ -25,14 +25,19 @@
</div> </div>
<br/> <br/>
<ServerComponent @rendermode="InteractiveServer"></ServerComponent> <div class="input-group mb-3">
<input type="text" class="form-control" placeholder="Search servers"
@bind-value="serverFilter"
@bind-value:event="oninput" />
<button class="btn btn-outline-secondary" type="button" id="button-search" @onclick="HandleSearch">Search</button>
</div>
<br/> <br/>
<a href="@($"/servers/add")" class="btn btn-primary">Add</a> <a href="@($"/servers/add")" class="btn btn-primary">Add</a>
<br/> <br/>
<ul> <ul>
@foreach(var server in servers) <Virtualize Items="this.servers" Context="server">
{ <li @key="server.Id">
<li>
@server.Name in @server.City is @server.Name in @server.City is
<span style="color:@(server.IsOnline ? "green" : "red")"> <span style="color:@(server.IsOnline ? "green" : "red")">
@(server.IsOnline ? "online" : "offline") @(server.IsOnline ? "online" : "offline")
@ -47,12 +52,23 @@
<button type="submit" class="btn btn-danger">Delete</button> <button type="submit" class="btn btn-danger">Delete</button>
</EditForm> </EditForm>
</li> </li>
} </Virtualize>
</ul> </ul>
@code { @code {
private List<string> cities = ServersRepository.GetCities(); private List<string> cities = ServersRepository.GetCities();
private List<Server> servers = ServersRepository.GetServersByCity("Eindhoven"); private List<Server> servers = ServersRepository.GetServersByCity("Eindhoven");
private string selectedCity = "Eindhoven";
private string _serverFilter = "";
private string serverFilter {
get => _serverFilter;
set
{
_serverFilter = value;
this.servers = ServersRepository.SearchServers(_serverFilter);
this.selectedCity = string.Empty;
}
}
private void DeleteServer(int serverId) private void DeleteServer(int serverId)
{ {
@ -62,4 +78,16 @@
NavigationManager.Refresh(); NavigationManager.Refresh();
} }
} }
private void SelectCity(string cityName)
{
this.selectedCity = cityName;
this.servers = ServersRepository.GetServersByCity(this.selectedCity);
}
private void HandleSearch()
{
this.servers = ServersRepository.SearchServers(serverFilter);
this.selectedCity = string.Empty;
}
} }

View File

@ -0,0 +1,5 @@
.card-body.active
{
background-color: #E3E3E3;
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>

View File

@ -1,8 +1,11 @@
{ {
"DetailedErrors": true,
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
"Default": "Information", "Default": "Information",
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.SignalR": "Debug"
} }
} }
} }