Compare commits
21 Commits
21e24945fd
...
a25e767b29
| Author | SHA1 | Date | |
|---|---|---|---|
| a25e767b29 | |||
| 28c3449e24 | |||
| 705e9493fe | |||
| 8cf581efca | |||
| 86e41b22ff | |||
| d6df2a448d | |||
| ae3f096722 | |||
| 2da0063331 | |||
| b041d7d244 | |||
| f2b9daac52 | |||
| b39211b1d5 | |||
| b9e4f44d5d | |||
| 5f7b63071e | |||
| 23d20f2f04 | |||
| ea9213f9c1 | |||
| 820682a8ba | |||
| 2c8b50e8c5 | |||
| e4ac3ab0d9 | |||
| 6b3b08b07a | |||
| 9396e98eea | |||
| f24cc284f7 |
@ -1,3 +1,4 @@
|
||||
@implements IDisposable
|
||||
|
||||
@if (cities != null && cities.Count > 0)
|
||||
{
|
||||
@ -9,18 +10,19 @@
|
||||
city="@city"
|
||||
selectedCity="@this.selectedCity"
|
||||
SelectCityCallBack="HandleCitySelection">
|
||||
</CityComponent>
|
||||
</CityComponent>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@code {
|
||||
private string selectedCity = "Eindhoven";
|
||||
private List<string> cities = ServersRepository.GetCities();
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<string> SelectCityCallBack { get; set; }
|
||||
[Parameter]
|
||||
public string? selectedCity { get; set; } = "Eindhoven";
|
||||
|
||||
public void ClearSelection()
|
||||
{
|
||||
@ -31,4 +33,10 @@
|
||||
this.selectedCity = cityName;
|
||||
SelectCityCallBack.InvokeAsync(cityName);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
var guid = Guid.NewGuid();
|
||||
Console.WriteLine($"CityListComponent: {nameof(Dispose)} : {guid}");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
@namespace ServerManagement.Components.Controls.Generic
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-2">
|
||||
<label class="col-form-label">@Label</label>
|
||||
</div>
|
||||
<div class="col-6 input-width">
|
||||
@Control
|
||||
</div>
|
||||
<div class="col">
|
||||
@ValidationControl
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public string? Label { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment? Control { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment? ValidationControl { get; set; }
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
@typeparam TItem
|
||||
|
||||
@Header
|
||||
@if (Items != null && Items.Count > 0 && Row != null)
|
||||
{
|
||||
<Virtualize Items="this.Items" Context="item">
|
||||
@Row(item)
|
||||
</Virtualize>
|
||||
}
|
||||
@Footer
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public List<TItem>? Items { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment<TItem>? Row { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment? Header { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment? Footer { get; set; }
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
<div class="input-group mb-3 input-width">
|
||||
<div class="input-group mb-3 input-width" @attributes="OtherAttributes">
|
||||
<input type="text" class="form-control" placeholder="Search servers"
|
||||
@bind-value="serverFilter"
|
||||
@bind-value:event="oninput" />
|
||||
@ -18,6 +18,10 @@
|
||||
[Parameter]
|
||||
public EventCallback<string> FilterSearchTerm { get; set; }
|
||||
|
||||
[Parameter(CaptureUnmatchedValues = true)]
|
||||
// Enables other HTML attributes like class, style, data-x, etc.
|
||||
public Dictionary<string, object>? OtherAttributes { get; set; }
|
||||
|
||||
private void HandleSearch()
|
||||
{
|
||||
FilterSearchTerm.InvokeAsync(serverFilter);
|
||||
|
||||
@ -4,53 +4,66 @@
|
||||
|
||||
@if (Server != null)
|
||||
{
|
||||
<li @key="Server.Id">
|
||||
@Server.Name in @Server.City is
|
||||
<span style="color:@(Server.IsOnline ? "green" : "red")">
|
||||
@(Server.IsOnline ? "online" : "offline")
|
||||
</span>;
|
||||
|
||||
@if (Server.IsOnline)
|
||||
{
|
||||
<button type="button" class="btn btn-outline-danger"
|
||||
@onclick="@(() => { Server.IsOnline = false; })">
|
||||
Turn off
|
||||
</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="btn btn-outline-success"
|
||||
@onclick="@(() => { Server.IsOnline = true; })">
|
||||
Turn on
|
||||
</button>
|
||||
}
|
||||
|
||||
@if (Server.IsOnline)
|
||||
{
|
||||
Random random = new Random();
|
||||
int randomNumber = random.Next(0, 500);
|
||||
<text>@randomNumber users online</text>
|
||||
}
|
||||
else
|
||||
{
|
||||
<text>N/A</text>
|
||||
}
|
||||
|
||||
<a href="@($"/servers/{Server.Id}")" class="btn btn-primary">Edit</a>
|
||||
|
||||
<EditForm
|
||||
Model="Server"
|
||||
FormName="@($"formDeleteServer{Server.Id}")"
|
||||
OnValidSubmit="@(() => { DeleteServer(Server.Id); })">
|
||||
<button type="submit" class="btn btn-danger">Delete</button>
|
||||
</EditForm>
|
||||
</li>
|
||||
<tr @key="Server.Id" style="background-color: @GetBackgroundColor();">
|
||||
<td>
|
||||
@Server.Name
|
||||
</td>
|
||||
<td>
|
||||
@Server.City
|
||||
</td>
|
||||
<td>
|
||||
<span style="color:@(Server.IsOnline ? "green" : "red")">
|
||||
@(Server.IsOnline ? "online" : "offline")
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
@if (Server.IsOnline)
|
||||
{
|
||||
Random random = new Random();
|
||||
int randomNumber = random.Next(0, 500);
|
||||
<text>@randomNumber users online</text>
|
||||
}
|
||||
else
|
||||
{
|
||||
<text>N/A</text>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@if (Server.IsOnline)
|
||||
{
|
||||
<button type="button" class="btn btn-outline-danger"
|
||||
@onclick="@(() => { Server.IsOnline = false; })">
|
||||
Turn off
|
||||
</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="btn btn-outline-success"
|
||||
@onclick="@(() => { Server.IsOnline = true; })">
|
||||
Turn on
|
||||
</button>
|
||||
}
|
||||
|
||||
<a href="@($"/server/{Server.Id}")" class="btn btn-primary">Edit</a>
|
||||
</td>
|
||||
<td>
|
||||
<EditForm
|
||||
Model="Server"
|
||||
FormName="@($"formDeleteServer{Server.Id}")"
|
||||
OnValidSubmit="@(() => { DeleteServer(Server.Id); })">
|
||||
<button type="submit" class="btn btn-danger">Delete</button>
|
||||
</EditForm>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public Server? Server { get; set; }
|
||||
|
||||
[CascadingParameter(Name="SelectedCity")]
|
||||
public string? SelectedCity { get; set; }
|
||||
|
||||
private void DeleteServer(int serverId)
|
||||
{
|
||||
if (serverId > 0)
|
||||
@ -59,4 +72,24 @@
|
||||
NavigationManager.Refresh(forceReload: true);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetBackgroundColor()
|
||||
{
|
||||
if (SelectedCity != null) {
|
||||
switch (this.SelectedCity)
|
||||
{
|
||||
case "Eindhoven": return "lightskyblue";
|
||||
case "Helmond": return "lightcoral";
|
||||
case "Oosterhout": return "lightgreen";
|
||||
case "Roosendaal": return "lightsalmon";
|
||||
case "Deurne": return "lightpink";
|
||||
default:
|
||||
return "white";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return "white";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,20 +1,62 @@
|
||||
@if (this.servers != null && this.servers.Count > 0)
|
||||
{
|
||||
<ul>
|
||||
<Virtualize Items="this.servers" Context="server">
|
||||
@using System.Threading;
|
||||
|
||||
<table class="table table-striped">
|
||||
<RepeaterComponent Items="this.servers">
|
||||
<Header>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>City</th>
|
||||
<th>Status</th>
|
||||
<th>People online</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
</Header>
|
||||
<Row Context="server">
|
||||
<ServerComponent server="server"></ServerComponent>
|
||||
</Virtualize>
|
||||
</ul>
|
||||
}
|
||||
</Row>
|
||||
<Footer>
|
||||
|
||||
</Footer>
|
||||
</RepeaterComponent>
|
||||
</table>
|
||||
|
||||
<button type="button" class="btn btn-primary" onclick=@(() => {base.InvokeAsync(StateHasChanged);})"">Refresh</button>
|
||||
|
||||
@code {
|
||||
private List<Server>? servers;
|
||||
private Timer? Timer;
|
||||
|
||||
[Parameter]
|
||||
public string? CityName { get; set; }
|
||||
[Parameter]
|
||||
public string SearchFilter { get; set; } = "";
|
||||
|
||||
public override Task SetParametersAsync(ParameterView parameters)
|
||||
{
|
||||
// Only trigger OnParametersSet if the parameter matches and has actually changed.
|
||||
// This saves expensive calls to the data repository.
|
||||
if (parameters.TryGetValue<string>("CityName", out var cityName))
|
||||
{
|
||||
if (cityName != CityName)
|
||||
{
|
||||
base.SetParametersAsync(parameters);
|
||||
}
|
||||
}
|
||||
|
||||
if (parameters.TryGetValue<string>("SearchFilter", out var searchFilter))
|
||||
{
|
||||
if (searchFilter != SearchFilter)
|
||||
{
|
||||
base.SetParametersAsync(parameters);
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(this.SearchFilter))
|
||||
@ -26,4 +68,27 @@
|
||||
servers = ServersRepository.SearchServers(SearchFilter);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
base.OnAfterRender(firstRender);
|
||||
|
||||
if (firstRender)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(this.SearchFilter))
|
||||
{
|
||||
servers = ServersRepository.GetServersByCity(CityName ?? "Eindhoven");
|
||||
}
|
||||
else
|
||||
{
|
||||
servers = ServersRepository.SearchServers(SearchFilter);
|
||||
}
|
||||
// Render the component again by letting it know the state changed.
|
||||
StateHasChanged();
|
||||
|
||||
Timer = new Timer(_ => {
|
||||
base.InvokeAsync(StateHasChanged);
|
||||
}, null, 4000, 4000);
|
||||
}
|
||||
}
|
||||
}
|
||||
32
ServerManagement/Components/Controls/ToDoItemComponent.razor
Normal file
32
ServerManagement/Components/Controls/ToDoItemComponent.razor
Normal file
@ -0,0 +1,32 @@
|
||||
@if (Item != null)
|
||||
{
|
||||
<li @key="Item.Id">
|
||||
<div class="row mb-2">
|
||||
<div class="col-1" style="width: 30px;">
|
||||
<input type="checkbox" class="form-check-input" style="vertical-align: middle" @bind-value="Item.IsCompleted" checked="@Item.IsCompleted"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
@if (Item.IsCompleted)
|
||||
{
|
||||
<input type="text" class="form-control border-0 text-decoration-line-through" style="vertical-align: middle" @bind-value="Item.Name" disabled/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input type="text" class="form-control border-0" style="vertical-align: middle" @bind-value="Item.Name"/>
|
||||
}
|
||||
</div>
|
||||
<div class="col">
|
||||
@if (Item.IsCompleted)
|
||||
{
|
||||
<text>Completed at: @Item.DateCompleted.ToLongDateString()</text>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public ToDoItem? Item { get; set; }
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
@if (Items != null)
|
||||
{
|
||||
@foreach (var item in Items)
|
||||
{
|
||||
<ToDoItemComponent Item="item"></ToDoItemComponent>
|
||||
}
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public List<ToDoItem>? Items { get; set; }
|
||||
}
|
||||
121
ServerManagement/Components/Pages/AddEditServer.razor
Normal file
121
ServerManagement/Components/Pages/AddEditServer.razor
Normal file
@ -0,0 +1,121 @@
|
||||
@page "/server/{id:int?}"
|
||||
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IJSRuntime JSRuntime
|
||||
|
||||
<NavigationLock
|
||||
OnBeforeInternalNavigation="OnBeforeInternalNavigation"
|
||||
ConfirmExternalNavigation="true">
|
||||
</NavigationLock>
|
||||
|
||||
@if (Id.HasValue)
|
||||
{
|
||||
<h3>Edit server</h3>
|
||||
}
|
||||
else
|
||||
{
|
||||
<h3>Add server</h3>
|
||||
}
|
||||
|
||||
@if (server != null)
|
||||
{
|
||||
<EditForm Model="server" FormName="formServer" OnValidSubmit="SubmitServer">
|
||||
<DataAnnotationsValidator></DataAnnotationsValidator>
|
||||
<ValidationSummary></ValidationSummary>
|
||||
|
||||
@if (server.Id > 0)
|
||||
{
|
||||
<InputNumber @bind-Value="server.Id" hidden></InputNumber>
|
||||
}
|
||||
|
||||
<FieldComponent Label="Name">
|
||||
<Control>
|
||||
<InputText @bind-Value="server.Name" class="form-control"></InputText>
|
||||
</Control>
|
||||
<ValidationControl>
|
||||
<ValidationMessage For="() => server.Name"></ValidationMessage>
|
||||
</ValidationControl>
|
||||
</FieldComponent>
|
||||
|
||||
<FieldComponent Label="City">
|
||||
<Control>
|
||||
<InputText @bind-Value="server.City" class="form-control"></InputText>
|
||||
</Control>
|
||||
<ValidationControl>
|
||||
<ValidationMessage For="() => server.City"></ValidationMessage>
|
||||
</ValidationControl>
|
||||
</FieldComponent>
|
||||
|
||||
<FieldComponent Label="Online">
|
||||
<Control>
|
||||
<InputCheckbox @bind-Value="server.IsOnline" class="form-check-input"></InputCheckbox>
|
||||
</Control>
|
||||
</FieldComponent>
|
||||
<br/>
|
||||
@if (server.Id > 0)
|
||||
{
|
||||
<button class="btn btn-primary" type="submit">Update</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button class="btn btn-primary" type="submit">Save</button>
|
||||
}
|
||||
|
||||
<a href="/servers" class="btn btn-primary">Close</a>
|
||||
</EditForm>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public int? Id { get; set; }
|
||||
|
||||
[SupplyParameterFromForm]
|
||||
private Server? server { get; set; }
|
||||
|
||||
[SupplyParameterFromQuery]
|
||||
public string? City { get; set; }
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if (this.Id.HasValue)
|
||||
{
|
||||
server ??= ServersRepository.GetServerById(this.Id.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
server ??= new Server() { IsOnline = false };
|
||||
}
|
||||
|
||||
if (server != null && !string.IsNullOrEmpty(this.City))
|
||||
{
|
||||
server.City = this.City;
|
||||
}
|
||||
}
|
||||
|
||||
private void SubmitServer()
|
||||
{
|
||||
if (server != null)
|
||||
{
|
||||
if (this.Id.HasValue)
|
||||
{
|
||||
ServersRepository.UpdateServer(server.Id, server);
|
||||
}
|
||||
else
|
||||
{
|
||||
ServersRepository.AddServer(server);
|
||||
}
|
||||
}
|
||||
|
||||
// An exception is raised when debugging from VS Code, but not when using dotnet watch.
|
||||
NavigationManager.NavigateTo($"/servers/back_from/{this.server?.City}");
|
||||
}
|
||||
|
||||
private async Task OnBeforeInternalNavigation(LocationChangingContext context)
|
||||
{
|
||||
var isConfirmed = await JSRuntime.InvokeAsync<bool>("confirm", "Are you sure you want to leave this page?");
|
||||
if (!isConfirmed)
|
||||
{
|
||||
context.PreventNavigation();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,59 +0,0 @@
|
||||
@page "/servers/add"
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
|
||||
@attribute [ExcludeFromInteractiveRouting]
|
||||
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<h3>Add server</h3>
|
||||
<br/>
|
||||
<br/>
|
||||
<EditForm Model="server" FormName="formServer" OnValidSubmit="SubmitServer">
|
||||
<DataAnnotationsValidator></DataAnnotationsValidator>
|
||||
<ValidationSummary></ValidationSummary>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-2">
|
||||
<label class="col-form-label">Name</label>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<InputText @bind-Value="server.Name" class="form-control"></InputText>
|
||||
</div>
|
||||
<div class="col">
|
||||
<ValidationMessage For="() => server.Name"></ValidationMessage>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-2">
|
||||
<label class="col-form-label">City</label>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<InputText @bind-Value="server.City" class="form-control"></InputText>
|
||||
</div>
|
||||
<div class="col">
|
||||
<ValidationMessage For="() => server.City"></ValidationMessage>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<button class="btn btn-primary" type="submit">Add</button>
|
||||
|
||||
<a href="/servers" class="btn btn-primary">Close</a>
|
||||
</EditForm>
|
||||
|
||||
|
||||
@code {
|
||||
[SupplyParameterFromForm(FormName = "formServer")]
|
||||
private Server server { get; set; } = new Server() { IsOnline = false };
|
||||
|
||||
private void SubmitServer()
|
||||
{
|
||||
if (server != null)
|
||||
{
|
||||
ServersRepository.AddServer(server);
|
||||
}
|
||||
|
||||
// An exception is raised when debugging from VS Code, but not when using dotnet watch.
|
||||
NavigationManager.NavigateTo("/servers");
|
||||
}
|
||||
}
|
||||
@ -1,78 +0,0 @@
|
||||
@page "/servers/{id:int}"
|
||||
@* Route constraints: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-9.0#route-constraints *@
|
||||
|
||||
@attribute [ExcludeFromInteractiveRouting]
|
||||
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<h3>Edit server</h3>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
@if (server != null)
|
||||
{
|
||||
<EditForm Model="server" FormName="formServer" OnValidSubmit="SubmitServer">
|
||||
<DataAnnotationsValidator></DataAnnotationsValidator>
|
||||
<ValidationSummary></ValidationSummary>
|
||||
<InputNumber @bind-Value="server.Id" hidden></InputNumber>
|
||||
<div class="row mb-3">
|
||||
<div class="col-2">
|
||||
<label class="col-form-label">Name</label>
|
||||
</div>
|
||||
<div class="col-6 input-width">
|
||||
<InputText @bind-Value="server.Name" class="form-control"></InputText>
|
||||
</div>
|
||||
<div class="col">
|
||||
<ValidationMessage For="() => server.Name"></ValidationMessage>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-2">
|
||||
<label class="col-form-label">City</label>
|
||||
</div>
|
||||
<div class="col-6 input-width">
|
||||
<InputText @bind-Value="server.City" class="form-control"></InputText>
|
||||
</div>
|
||||
<div class="col">
|
||||
<ValidationMessage For="() => server.City"></ValidationMessage>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-2">
|
||||
<label class="col-form-label">Online</label>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<InputCheckbox @bind-Value="server.IsOnline" class="form-check-input"></InputCheckbox>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<button class="btn btn-primary" type="submit">Update</button>
|
||||
|
||||
<a href="/servers" class="btn btn-primary">Close</a>
|
||||
</EditForm>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter] // This is a root parameter.
|
||||
public int Id { get; set; }
|
||||
|
||||
[SupplyParameterFromForm(FormName = "formServer")]
|
||||
private Server? server { get; set; }
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
server ??= ServersRepository.GetServerById(this.Id);
|
||||
}
|
||||
|
||||
private void SubmitServer()
|
||||
{
|
||||
if (server != null)
|
||||
{
|
||||
ServersRepository.UpdateServer(server.Id, server);
|
||||
}
|
||||
|
||||
// An exception is raised when debugging from VS Code, but not when using dotnet watch.
|
||||
NavigationManager.NavigateTo("/servers");
|
||||
}
|
||||
}
|
||||
76
ServerManagement/Components/Pages/QuickGridDemo.razor
Normal file
76
ServerManagement/Components/Pages/QuickGridDemo.razor
Normal file
@ -0,0 +1,76 @@
|
||||
@page "/quickgrid"
|
||||
@using Microsoft.AspNetCore.Components.QuickGrid
|
||||
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<h3>QuickGrid demo</h3>
|
||||
<br/>
|
||||
|
||||
@if (servers != null)
|
||||
{
|
||||
<QuickGrid Items="servers.AsQueryable()" Pagination="paginationState">
|
||||
<PropertyColumn Property="s => s.Name" Sortable="true"></PropertyColumn>
|
||||
<PropertyColumn Property="s => s.City" Sortable="true"></PropertyColumn>
|
||||
<TemplateColumn Title="Status" Sortable="true" SortBy="GridSort<Server>.ByAscending(s => s.IsOnline)">
|
||||
<div style="color: @(context.IsOnline ? "green" : "red")">
|
||||
@(context.IsOnline ? "Online" : "Offline")
|
||||
</div>
|
||||
</TemplateColumn>
|
||||
<TemplateColumn Title="People online">
|
||||
@if (context.IsOnline)
|
||||
{
|
||||
Random random = new Random();
|
||||
int randomNumber = random.Next(0, 500);
|
||||
<text>@randomNumber users online</text>
|
||||
}
|
||||
else
|
||||
{
|
||||
<text>N/A</text>
|
||||
}
|
||||
</TemplateColumn>
|
||||
<TemplateColumn>
|
||||
@if (context.IsOnline)
|
||||
{
|
||||
<button type="button" class="btn btn-outline-danger"
|
||||
@onclick="@(() => { context.IsOnline = false; })">
|
||||
Turn off
|
||||
</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="btn btn-outline-success"
|
||||
@onclick="@(() => { context.IsOnline = true; })">
|
||||
Turn on
|
||||
</button>
|
||||
}
|
||||
</TemplateColumn>
|
||||
<TemplateColumn>
|
||||
<a href="@($"/servers/{context.Id}")" class="btn btn-primary">Edit</a>
|
||||
</TemplateColumn>
|
||||
|
||||
<TemplateColumn>
|
||||
<ChildContent Context="server">
|
||||
<EditForm
|
||||
Model="server"
|
||||
FormName="@($"formDeleteServer{server.Id}")"
|
||||
OnValidSubmit="@(() => { DeleteServer(server.Id); })">
|
||||
<button type="submit" class="btn btn-danger">Delete</button>
|
||||
</EditForm>
|
||||
</ChildContent>
|
||||
</TemplateColumn>
|
||||
</QuickGrid>
|
||||
<Paginator State="paginationState"></Paginator>
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<Server>? servers = ServersRepository.GetServers();
|
||||
private PaginationState paginationState = new PaginationState { ItemsPerPage = 5 };
|
||||
private void DeleteServer(int serverId)
|
||||
{
|
||||
if (serverId > 0)
|
||||
{
|
||||
ServersRepository.DeleteServer(serverId);
|
||||
NavigationManager.Refresh(forceReload: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,23 +1,38 @@
|
||||
@page "/servers"
|
||||
@page "/servers/back_from/{cityName}"
|
||||
@using ServerManagement.Components.Controls
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<h3>Servers</h3>
|
||||
<br/>
|
||||
<br/>
|
||||
<CityListComponent @ref="cityListComponent" SelectCityCallBack="HandleCitySelection"></CityListComponent>
|
||||
<CityListComponent
|
||||
@ref="cityListComponent"
|
||||
SelectCityCallBack="HandleCitySelection"
|
||||
selectedCity="@this.selectedCity">
|
||||
</CityListComponent>
|
||||
<br/>
|
||||
<SearchBarComponent @ref="searchBarComponent" FilterSearchTerm="HandleSearch"></SearchBarComponent>
|
||||
<SearchBarComponent
|
||||
@ref="searchBarComponent"
|
||||
FilterSearchTerm="HandleSearch"
|
||||
style="width: 600px">
|
||||
</SearchBarComponent>
|
||||
<br/>
|
||||
<a href="@($"/servers/add")" class="btn btn-primary">Add</a>
|
||||
<a href="@($"/server")" class="btn btn-primary">Add Server</a>
|
||||
|
||||
<a href="@($"/servername")" class="btn btn-primary">Wizard</a>
|
||||
<br/>
|
||||
|
||||
<ServerListComponent
|
||||
CityName="@this.selectedCity"
|
||||
SearchFilter="@this.searchFilter">
|
||||
|
||||
</ServerListComponent>
|
||||
<CascadingValue Name="SelectedCity" Value="@selectedCity">
|
||||
<ServerListComponent
|
||||
CityName="@this.selectedCity"
|
||||
SearchFilter="@this.searchFilter">
|
||||
</ServerListComponent>
|
||||
</CascadingValue>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public string? CityName { get; set; }
|
||||
private string selectedCity = "Eindhoven";
|
||||
private string searchFilter = "";
|
||||
private CityListComponent? cityListComponent;
|
||||
@ -35,4 +50,16 @@
|
||||
this.searchFilter = searchFilter;
|
||||
cityListComponent?.ClearSelection();
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
if (NavigationManager.Uri.Contains("back_from") && !string.IsNullOrWhiteSpace(CityName))
|
||||
{
|
||||
selectedCity = CityName;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -10,32 +10,7 @@
|
||||
@if (items != null && items.Count > 0)
|
||||
{
|
||||
<ul class="list-unstyled">
|
||||
@foreach (var item in items)
|
||||
{
|
||||
<li @key="item.Id">
|
||||
<div class="row mb-2">
|
||||
<div class="col-1" style="width: 30px;">
|
||||
<input type="checkbox" class="form-check-input" style="vertical-align: middle" @bind-value="item.IsCompleted" checked="@item.IsCompleted"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
@if (item.IsCompleted)
|
||||
{
|
||||
<input type="text" class="form-control border-0 text-decoration-line-through" style="vertical-align: middle" @bind-value="item.Name" disabled/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input type="text" class="form-control border-0" style="vertical-align: middle" @bind-value="item.Name"/>
|
||||
}
|
||||
</div>
|
||||
<div class="col">
|
||||
@if (item.IsCompleted)
|
||||
{
|
||||
<text>Completed at: @item.DateCompleted.ToLongDateString()</text>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
}
|
||||
<ToDoItemListComponent Items="items"></ToDoItemListComponent>
|
||||
</ul>
|
||||
}
|
||||
|
||||
|
||||
65
ServerManagement/Components/Pages/Wizards/SetCityName.razor
Normal file
65
ServerManagement/Components/Pages/Wizards/SetCityName.razor
Normal file
@ -0,0 +1,65 @@
|
||||
@page "/cityname"
|
||||
|
||||
@using ServerManagement.StateStore
|
||||
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject SessionStorage sessionStorage
|
||||
|
||||
<h3>City Name</h3>
|
||||
<br/>
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(errorMessage))
|
||||
{
|
||||
<div class="alert alert-danger">
|
||||
@errorMessage
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (server != null)
|
||||
{
|
||||
<FieldComponent Label="City name">
|
||||
<Control>
|
||||
<input type="text" @bind-value="server.City" class="form-control"></input>
|
||||
</Control>
|
||||
</FieldComponent>
|
||||
<br/>
|
||||
<button type="button" class="btn btn-primary" @onclick="GoNext">Next</button>
|
||||
}
|
||||
|
||||
@code {
|
||||
private Server? server;
|
||||
private string? errorMessage;
|
||||
|
||||
[SupplyParameterFromQuery]
|
||||
private string? ServerName { get; set; }
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
this.server = await sessionStorage.GetServerAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GoNext()
|
||||
{
|
||||
if (server != null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(server.City))
|
||||
{
|
||||
this.errorMessage = "City name is required.";
|
||||
}
|
||||
else
|
||||
{
|
||||
await this.sessionStorage.SetServerAsync(server);
|
||||
NavigationManager.NavigateTo($"/serverstatus");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
@page "/servername"
|
||||
|
||||
@using ServerManagement.StateStore
|
||||
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject SessionStorage sessionStorage
|
||||
|
||||
<h3>Server Name</h3>
|
||||
<br/>
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(errorMessage))
|
||||
{
|
||||
<div class="alert alert-danger">
|
||||
@errorMessage
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (server != null)
|
||||
{
|
||||
<FieldComponent Label="Server name">
|
||||
<Control>
|
||||
<input type="text" @bind-value="server.Name" class="form-control"></input>
|
||||
</Control>
|
||||
</FieldComponent>
|
||||
<br/>
|
||||
<button type="button" class="btn btn-primary" @onclick="GoNext">Next</button>
|
||||
}
|
||||
|
||||
@code {
|
||||
private Server? server;
|
||||
private string? errorMessage;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
server = new Server();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GoNext()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(server?.Name))
|
||||
{
|
||||
this.errorMessage = "Server name is required.";
|
||||
}
|
||||
else
|
||||
{
|
||||
await sessionStorage.SetServerAsync(server);
|
||||
NavigationManager.NavigateTo($"/cityname");
|
||||
}
|
||||
}
|
||||
}
|
||||
55
ServerManagement/Components/Pages/Wizards/SetStatus.razor
Normal file
55
ServerManagement/Components/Pages/Wizards/SetStatus.razor
Normal file
@ -0,0 +1,55 @@
|
||||
@page "/serverstatus"
|
||||
|
||||
@using ServerManagement.StateStore
|
||||
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject SessionStorage sessionStorage
|
||||
|
||||
<h3>Server Status</h3>
|
||||
<br/>
|
||||
|
||||
@if (server != null)
|
||||
{
|
||||
<FieldComponent Label="Server status online">
|
||||
<Control>
|
||||
@if (server.IsOnline)
|
||||
{
|
||||
<input type="checkbox" @bind-value="server.IsOnline" class="form-check-input"></input>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input type="checkbox" @bind-value="server.IsOnline" class="form-check-input" checked></input>
|
||||
}
|
||||
</Control>
|
||||
</FieldComponent>
|
||||
<br/>
|
||||
<button type="button" class="btn btn-primary" @onclick="Save">Save</button>
|
||||
}
|
||||
|
||||
@code {
|
||||
private Server? server;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
this.server = await sessionStorage.GetServerAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Save()
|
||||
{
|
||||
if (server != null)
|
||||
{
|
||||
await sessionStorage.SetServerAsync(null);
|
||||
ServersRepository.AddServer(server);
|
||||
NavigationManager.NavigateTo($"/servers/back_from/{server?.City}");
|
||||
}
|
||||
}
|
||||
}
|
||||
33
ServerManagement/Components/StateStore/SessionStorage.cs
Normal file
33
ServerManagement/Components/StateStore/SessionStorage.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
|
||||
using ServerManagement.Models;
|
||||
|
||||
namespace ServerManagement.StateStore
|
||||
{
|
||||
public class SessionStorage
|
||||
{
|
||||
private readonly ProtectedSessionStorage protectedSessionStorage;
|
||||
|
||||
public SessionStorage(ProtectedSessionStorage protectedSessionStorage)
|
||||
{
|
||||
this.protectedSessionStorage = protectedSessionStorage;
|
||||
}
|
||||
|
||||
public async Task<Server?> GetServerAsync()
|
||||
{
|
||||
var result = await this.protectedSessionStorage.GetAsync<Server>("server");
|
||||
if (result.Success)
|
||||
{
|
||||
return result.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SetServerAsync(Server? server)
|
||||
{
|
||||
await this.protectedSessionStorage.SetAsync("server", server);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,4 +9,6 @@
|
||||
@using ServerManagement
|
||||
@using ServerManagement.Components
|
||||
@using ServerManagement.Components.Controls
|
||||
@using ServerManagement.Models
|
||||
@using ServerManagement.Components.Controls.Generic
|
||||
@using ServerManagement.Models
|
||||
@using ServerManagement.StateStore
|
||||
@ -1,4 +1,5 @@
|
||||
using ServerManagement.Components;
|
||||
using ServerManagement.StateStore;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
@ -6,6 +7,8 @@ var builder = WebApplication.CreateBuilder(args);
|
||||
builder.Services.AddRazorComponents()
|
||||
.AddInteractiveServerComponents(); // Provides server interactivity.
|
||||
|
||||
builder.Services.AddTransient<SessionStorage>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
|
||||
@ -10,4 +10,8 @@
|
||||
<RazorComponent Include="Components\Controls\ServerComponent.razor" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.QuickGrid" Version="9.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user