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)
|
@if (cities != null && cities.Count > 0)
|
||||||
{
|
{
|
||||||
@ -9,18 +10,19 @@
|
|||||||
city="@city"
|
city="@city"
|
||||||
selectedCity="@this.selectedCity"
|
selectedCity="@this.selectedCity"
|
||||||
SelectCityCallBack="HandleCitySelection">
|
SelectCityCallBack="HandleCitySelection">
|
||||||
</CityComponent>
|
</CityComponent>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private string selectedCity = "Eindhoven";
|
|
||||||
private List<string> cities = ServersRepository.GetCities();
|
private List<string> cities = ServersRepository.GetCities();
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public EventCallback<string> SelectCityCallBack { get; set; }
|
public EventCallback<string> SelectCityCallBack { get; set; }
|
||||||
|
[Parameter]
|
||||||
|
public string? selectedCity { get; set; } = "Eindhoven";
|
||||||
|
|
||||||
public void ClearSelection()
|
public void ClearSelection()
|
||||||
{
|
{
|
||||||
@ -31,4 +33,10 @@
|
|||||||
this.selectedCity = cityName;
|
this.selectedCity = cityName;
|
||||||
SelectCityCallBack.InvokeAsync(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"
|
<input type="text" class="form-control" placeholder="Search servers"
|
||||||
@bind-value="serverFilter"
|
@bind-value="serverFilter"
|
||||||
@bind-value:event="oninput" />
|
@bind-value:event="oninput" />
|
||||||
@ -18,6 +18,10 @@
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public EventCallback<string> FilterSearchTerm { get; set; }
|
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()
|
private void HandleSearch()
|
||||||
{
|
{
|
||||||
FilterSearchTerm.InvokeAsync(serverFilter);
|
FilterSearchTerm.InvokeAsync(serverFilter);
|
||||||
|
|||||||
@ -4,53 +4,66 @@
|
|||||||
|
|
||||||
@if (Server != null)
|
@if (Server != null)
|
||||||
{
|
{
|
||||||
<li @key="Server.Id">
|
<tr @key="Server.Id" style="background-color: @GetBackgroundColor();">
|
||||||
@Server.Name in @Server.City is
|
<td>
|
||||||
<span style="color:@(Server.IsOnline ? "green" : "red")">
|
@Server.Name
|
||||||
@(Server.IsOnline ? "online" : "offline")
|
</td>
|
||||||
</span>;
|
<td>
|
||||||
|
@Server.City
|
||||||
@if (Server.IsOnline)
|
</td>
|
||||||
{
|
<td>
|
||||||
<button type="button" class="btn btn-outline-danger"
|
<span style="color:@(Server.IsOnline ? "green" : "red")">
|
||||||
@onclick="@(() => { Server.IsOnline = false; })">
|
@(Server.IsOnline ? "online" : "offline")
|
||||||
Turn off
|
</span>
|
||||||
</button>
|
</td>
|
||||||
}
|
<td>
|
||||||
else
|
@if (Server.IsOnline)
|
||||||
{
|
{
|
||||||
<button type="button" class="btn btn-outline-success"
|
Random random = new Random();
|
||||||
@onclick="@(() => { Server.IsOnline = true; })">
|
int randomNumber = random.Next(0, 500);
|
||||||
Turn on
|
<text>@randomNumber users online</text>
|
||||||
</button>
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
@if (Server.IsOnline)
|
<text>N/A</text>
|
||||||
{
|
}
|
||||||
Random random = new Random();
|
</td>
|
||||||
int randomNumber = random.Next(0, 500);
|
<td>
|
||||||
<text>@randomNumber users online</text>
|
@if (Server.IsOnline)
|
||||||
}
|
{
|
||||||
else
|
<button type="button" class="btn btn-outline-danger"
|
||||||
{
|
@onclick="@(() => { Server.IsOnline = false; })">
|
||||||
<text>N/A</text>
|
Turn off
|
||||||
}
|
</button>
|
||||||
|
}
|
||||||
<a href="@($"/servers/{Server.Id}")" class="btn btn-primary">Edit</a>
|
else
|
||||||
|
{
|
||||||
<EditForm
|
<button type="button" class="btn btn-outline-success"
|
||||||
Model="Server"
|
@onclick="@(() => { Server.IsOnline = true; })">
|
||||||
FormName="@($"formDeleteServer{Server.Id}")"
|
Turn on
|
||||||
OnValidSubmit="@(() => { DeleteServer(Server.Id); })">
|
</button>
|
||||||
<button type="submit" class="btn btn-danger">Delete</button>
|
}
|
||||||
</EditForm>
|
|
||||||
</li>
|
<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 {
|
@code {
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Server? Server { get; set; }
|
public Server? Server { get; set; }
|
||||||
|
|
||||||
|
[CascadingParameter(Name="SelectedCity")]
|
||||||
|
public string? SelectedCity { get; set; }
|
||||||
|
|
||||||
private void DeleteServer(int serverId)
|
private void DeleteServer(int serverId)
|
||||||
{
|
{
|
||||||
if (serverId > 0)
|
if (serverId > 0)
|
||||||
@ -59,4 +72,24 @@
|
|||||||
NavigationManager.Refresh(forceReload: true);
|
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)
|
@using System.Threading;
|
||||||
{
|
|
||||||
<ul>
|
<table class="table table-striped">
|
||||||
<Virtualize Items="this.servers" Context="server">
|
<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>
|
<ServerComponent server="server"></ServerComponent>
|
||||||
</Virtualize>
|
</Row>
|
||||||
</ul>
|
<Footer>
|
||||||
}
|
|
||||||
|
</Footer>
|
||||||
|
</RepeaterComponent>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<button type="button" class="btn btn-primary" onclick=@(() => {base.InvokeAsync(StateHasChanged);})"">Refresh</button>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<Server>? servers;
|
private List<Server>? servers;
|
||||||
|
private Timer? Timer;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string? CityName { get; set; }
|
public string? CityName { get; set; }
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string SearchFilter { get; set; } = "";
|
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()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(this.SearchFilter))
|
if (string.IsNullOrWhiteSpace(this.SearchFilter))
|
||||||
@ -26,4 +68,27 @@
|
|||||||
servers = ServersRepository.SearchServers(SearchFilter);
|
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"
|
||||||
|
@page "/servers/back_from/{cityName}"
|
||||||
@using ServerManagement.Components.Controls
|
@using ServerManagement.Components.Controls
|
||||||
|
@inject NavigationManager NavigationManager
|
||||||
|
|
||||||
<h3>Servers</h3>
|
<h3>Servers</h3>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<CityListComponent @ref="cityListComponent" SelectCityCallBack="HandleCitySelection"></CityListComponent>
|
<CityListComponent
|
||||||
|
@ref="cityListComponent"
|
||||||
|
SelectCityCallBack="HandleCitySelection"
|
||||||
|
selectedCity="@this.selectedCity">
|
||||||
|
</CityListComponent>
|
||||||
<br/>
|
<br/>
|
||||||
<SearchBarComponent @ref="searchBarComponent" FilterSearchTerm="HandleSearch"></SearchBarComponent>
|
<SearchBarComponent
|
||||||
|
@ref="searchBarComponent"
|
||||||
|
FilterSearchTerm="HandleSearch"
|
||||||
|
style="width: 600px">
|
||||||
|
</SearchBarComponent>
|
||||||
<br/>
|
<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/>
|
<br/>
|
||||||
|
|
||||||
<ServerListComponent
|
<CascadingValue Name="SelectedCity" Value="@selectedCity">
|
||||||
CityName="@this.selectedCity"
|
<ServerListComponent
|
||||||
SearchFilter="@this.searchFilter">
|
CityName="@this.selectedCity"
|
||||||
|
SearchFilter="@this.searchFilter">
|
||||||
</ServerListComponent>
|
</ServerListComponent>
|
||||||
|
</CascadingValue>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public string? CityName { get; set; }
|
||||||
private string selectedCity = "Eindhoven";
|
private string selectedCity = "Eindhoven";
|
||||||
private string searchFilter = "";
|
private string searchFilter = "";
|
||||||
private CityListComponent? cityListComponent;
|
private CityListComponent? cityListComponent;
|
||||||
@ -35,4 +50,16 @@
|
|||||||
this.searchFilter = searchFilter;
|
this.searchFilter = searchFilter;
|
||||||
cityListComponent?.ClearSelection();
|
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)
|
@if (items != null && items.Count > 0)
|
||||||
{
|
{
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
@foreach (var item in items)
|
<ToDoItemListComponent Items="items"></ToDoItemListComponent>
|
||||||
{
|
|
||||||
<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>
|
|
||||||
}
|
|
||||||
</ul>
|
</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
|
||||||
@using ServerManagement.Components
|
@using ServerManagement.Components
|
||||||
@using ServerManagement.Components.Controls
|
@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.Components;
|
||||||
|
using ServerManagement.StateStore;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
@ -6,6 +7,8 @@ var builder = WebApplication.CreateBuilder(args);
|
|||||||
builder.Services.AddRazorComponents()
|
builder.Services.AddRazorComponents()
|
||||||
.AddInteractiveServerComponents(); // Provides server interactivity.
|
.AddInteractiveServerComponents(); // Provides server interactivity.
|
||||||
|
|
||||||
|
builder.Services.AddTransient<SessionStorage>();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
|
|||||||
@ -10,4 +10,8 @@
|
|||||||
<RazorComponent Include="Components\Controls\ServerComponent.razor" />
|
<RazorComponent Include="Components\Controls\ServerComponent.razor" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Components.QuickGrid" Version="9.0.3" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user