Merge branch 'unify-pickable-columns'

dhcp-server
Pat Hartl 2023-09-04 02:03:01 -05:00
commit 0a27689c72
4 changed files with 180 additions and 226 deletions

View File

@ -0,0 +1,72 @@
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
@inject ProtectedLocalStorage BrowserStorage
<Drawer Closable="true" Visible="@Visible" Placement="right" Title="@("Columns")" OnClose="() => Close()">
<Space Direction="@DirectionVHType.Vertical">
@foreach (var column in ColumnVisibility.Keys)
{
<SpaceItem>
<Switch Checked="ColumnVisibility[column]" OnChange="(state) => ChangeColumnVisibility(column, state)" /> @column
</SpaceItem>
}
</Space>
</Drawer>
@code {
[Parameter] public string Key { get; set; }
[Parameter] public bool Visible { get; set; }
[Parameter] public EventCallback<bool> VisibleChanged { get; set; }
Dictionary<string, bool> ColumnVisibility = new Dictionary<string, bool>();
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
try
{
var storedColumnVisibility = await BrowserStorage.GetAsync<Dictionary<string, bool>>($"Views.{Key}.ColumnPicker");
if (storedColumnVisibility.Success && storedColumnVisibility.Value != null)
ColumnVisibility = storedColumnVisibility.Value;
StateHasChanged();
}
catch
{
ColumnVisibility = new Dictionary<string, bool>();
await BrowserStorage.SetAsync($"Views.{Key}.FieldPicker", ColumnVisibility);
}
}
}
public bool IsColumnHidden(string columnName, bool isDefault = true)
{
if (!ColumnVisibility.ContainsKey(columnName))
ColumnVisibility[columnName] = isDefault;
return !ColumnVisibility[columnName];
}
protected override void OnParametersSet()
{
base.OnParametersSet();
if (ColumnVisibility == null)
ColumnVisibility = new Dictionary<string, bool>();
}
async Task ChangeColumnVisibility(string column, bool state)
{
ColumnVisibility[column] = state;
await InvokeAsync(StateHasChanged);
}
async Task Close()
{
Visible = false;
await VisibleChanged.InvokeAsync();
}
}

View File

@ -7,7 +7,6 @@
@attribute [Authorize]
@inject GameService GameService
@inject NavigationManager NavigationManager
@inject ProtectedLocalStorage BrowserStorage
<PageHeader Title="Games">
<PageHeaderExtra>
@ -22,159 +21,79 @@
</PageHeaderExtra>
</PageHeader>
<Drawer Closable="true" Visible="@FieldPickerVisible" Placement="right" Title="@("Fields")" OnClose="() => CloseFieldPicker()">
<Space Direction="@DirectionVHType.Vertical">
<SpaceItem><Switch Checked="FieldVisible(Field.Icon)" OnChange="(state) => ChangeFieldVisibility(Field.Icon, state)" /> @Field.Icon.GetDisplayName()</SpaceItem>
<SpaceItem><Switch Checked="FieldVisible(Field.Title)" OnChange="(state) => ChangeFieldVisibility(Field.Title, state)" /> @Field.Title.GetDisplayName()</SpaceItem>
<SpaceItem><Switch Checked="FieldVisible(Field.SortTitle)" OnChange="(state) => ChangeFieldVisibility(Field.SortTitle, state)" /> @Field.SortTitle.GetDisplayName()</SpaceItem>
<SpaceItem><Switch Checked="FieldVisible(Field.ReleasedOn)" OnChange="(state) => ChangeFieldVisibility(Field.ReleasedOn, state)" /> @Field.ReleasedOn.GetDisplayName()</SpaceItem>
<SpaceItem><Switch Checked="FieldVisible(Field.CreatedOn)" OnChange="(state) => ChangeFieldVisibility(Field.CreatedOn, state)" /> @Field.CreatedOn.GetDisplayName()</SpaceItem>
<SpaceItem><Switch Checked="FieldVisible(Field.CreatedBy)" OnChange="(state) => ChangeFieldVisibility(Field.CreatedBy, state)" /> @Field.CreatedBy.GetDisplayName()</SpaceItem>
<SpaceItem><Switch Checked="FieldVisible(Field.UpdatedOn)" OnChange="(state) => ChangeFieldVisibility(Field.UpdatedOn, state)" /> @Field.UpdatedOn.GetDisplayName()</SpaceItem>
<SpaceItem><Switch Checked="FieldVisible(Field.UpdatedBy)" OnChange="(state) => ChangeFieldVisibility(Field.UpdatedBy, state)" /> @Field.UpdatedBy.GetDisplayName()</SpaceItem>
<SpaceItem><Switch Checked="FieldVisible(Field.Singleplayer)" OnChange="(state) => ChangeFieldVisibility(Field.Singleplayer, state)" /> @Field.Singleplayer.GetDisplayName()</SpaceItem>
<SpaceItem><Switch Checked="FieldVisible(Field.Multiplayer)" OnChange="(state) => ChangeFieldVisibility(Field.Multiplayer, state)" /> @Field.Multiplayer.GetDisplayName()</SpaceItem>
<SpaceItem><Switch Checked="FieldVisible(Field.TotalKeys)" OnChange="(state) => ChangeFieldVisibility(Field.TotalKeys, state)" /> @Field.TotalKeys.GetDisplayName()</SpaceItem>
<SpaceItem><Switch Checked="FieldVisible(Field.KeysAllocated)" OnChange="(state) => ChangeFieldVisibility(Field.KeysAllocated, state)" /> @Field.KeysAllocated.GetDisplayName()</SpaceItem>
<SpaceItem><Switch Checked="FieldVisible(Field.Developers)" OnChange="(state) => ChangeFieldVisibility(Field.Developers, state)" /> @Field.Developers.GetDisplayName()</SpaceItem>
<SpaceItem><Switch Checked="FieldVisible(Field.Publishers)" OnChange="(state) => ChangeFieldVisibility(Field.Publishers, state)" /> @Field.Publishers.GetDisplayName()</SpaceItem>
<SpaceItem><Switch Checked="FieldVisible(Field.Genres)" OnChange="(state) => ChangeFieldVisibility(Field.Genres, state)" /> @Field.Genres.GetDisplayName()</SpaceItem>
<SpaceItem><Switch Checked="FieldVisible(Field.MultiplayerModes)" OnChange="(state) => ChangeFieldVisibility(Field.MultiplayerModes, state)" /> @Field.MultiplayerModes.GetDisplayName()</SpaceItem>
<SpaceItem><Switch Checked="FieldVisible(Field.ArchiveSize)" OnChange="(state) => ChangeFieldVisibility(Field.ArchiveSize, state)" /> @Field.ArchiveSize.GetDisplayName()</SpaceItem>
</Space>
</Drawer>
<TableColumnPicker @ref="Picker" Key="Games" @bind-Visible="ColumnPickerVisible" />
<Table @ref="Table" TItem="Game" DataSource="@Games" Loading="@Loading" PageSize="25">
@if (FieldVisible(Field.Icon))
{
<Column TData="string">
<Image Src="@GetIcon(context)" Height="32" Width="32" Preview="false"></Image>
</Column>
}
<Table TItem="Game" DataSource="@Games" Loading="@Loading" PageSize="25" Responsive>
<Column TData="string" Title="Icon" Hidden="@(Picker.IsColumnHidden("Icon"))">
<Image Src="@GetIcon(context)" Height="32" Width="32" Preview="false"></Image>
</Column>
@if (FieldVisible(Field.Title))
{
<PropertyColumn Property="g => g.Title" Sortable Filterable />
}
@if (FieldVisible(Field.SortTitle))
{
<PropertyColumn Property="g => g.SortTitle" Title="@Field.SortTitle.GetDisplayName()" Sortable Filterable />
}
@if (FieldVisible(Field.ReleasedOn))
{
<PropertyColumn Property="g => g.ReleasedOn" Format="MM/dd/yyyy" Sortable Filterable />
}
@if (FieldVisible(Field.CreatedOn))
{
<PropertyColumn Property="g => g.CreatedOn" Format="MM/dd/yyyy hh:mm tt" Sortable />
}
<PropertyColumn Property="g => g.Title" Sortable Filterable Hidden="@(Picker.IsColumnHidden("Title"))" />
@if (FieldVisible(Field.CreatedBy))
{
<PropertyColumn Property="g => g.CreatedBy" Sortable>
@context.CreatedBy?.UserName
</PropertyColumn>
}
<PropertyColumn Property="g => g.SortTitle" Title="Sort Title" Sortable Filterable Hidden="@(Picker.IsColumnHidden("Sort Title", false))" />
<PropertyColumn Property="g => g.ReleasedOn" Format="MM/dd/yyyy" Sortable Filterable Hidden="@(Picker.IsColumnHidden("Released On"))" />
<PropertyColumn Property="g => g.CreatedOn" Format="MM/dd/yyyy hh:mm tt" Sortable Hidden="@(Picker.IsColumnHidden("Created On"))" />
<PropertyColumn Property="g => g.CreatedBy" Sortable Hidden="@(Picker.IsColumnHidden("Created By"))">
@context.CreatedBy?.UserName
</PropertyColumn>
<PropertyColumn Property="g => g.UpdatedOn" Format="MM/dd/yyyy hh:mm tt" Sortable Hidden="@(Picker.IsColumnHidden("Updated On", false))" />
<PropertyColumn Property="g => g.UpdatedBy" Sortable Hidden="@(Picker.IsColumnHidden("Updated By", false))">
@context.UpdatedBy?.UserName
</PropertyColumn>
<PropertyColumn Property="g => g.Singleplayer" Sortable Filterable Hidden="@(Picker.IsColumnHidden("Singleplayer", false))">
<Checkbox Disabled="true" Checked="context.Singleplayer" />
</PropertyColumn>
<Column TData="bool" Title="Multiplayer" Hidden="@(Picker.IsColumnHidden("Multiplayer", false))">
<Checkbox Disabled="true" Checked="context.MultiplayerModes?.Count > 0" />
</Column>
@if (FieldVisible(Field.UpdatedOn))
{
<PropertyColumn Property="g => g.UpdatedOn" Format="MM/dd/yyyy hh:mm tt" Sortable />
}
<Column TData="int" Title="Total Keys" Hidden="@(Picker.IsColumnHidden("Total Keys"))">
@context.Keys?.Count
</Column>
@if (FieldVisible(Field.UpdatedBy))
{
<PropertyColumn Property="g => g.UpdatedBy" Sortable>
@context.UpdatedBy?.UserName
</PropertyColumn>
}
<Column TData="int" Title="Keys Allocated" Hidden="@(Picker.IsColumnHidden("Keys Allocated"))">
@context.Keys?.Count(k => k.ClaimedOn.HasValue)
</Column>
@if (FieldVisible(Field.Singleplayer))
{
<PropertyColumn Property="g => g.Singleplayer" Sortable Filterable>
<Checkbox Disabled="true" Checked="context.Singleplayer" />
</PropertyColumn>
}
<Column TData="string[]" Title="Developers" Hidden="@(Picker.IsColumnHidden("Developers", false))">
@foreach (var dev in context.Developers)
{
<Tag>@dev.Name</Tag>
}
</Column>
@if (FieldVisible(Field.Multiplayer))
{
<Column TData="bool" Title="@Field.Multiplayer.GetDisplayName()">
<Checkbox Disabled="true" Checked="context.MultiplayerModes?.Count > 0" />
</Column>
}
<Column TData="string[]" Title="Publishers" Hidden="@(Picker.IsColumnHidden("Publishers", false))">
@foreach (var pub in context.Publishers)
{
<Tag>@pub.Name</Tag>
}
</Column>
@if (FieldVisible(Field.TotalKeys))
{
<Column TData="int" Title="@Field.TotalKeys.GetDisplayName()">
@context.Keys?.Count
</Column>
}
<Column TData="string[]" Title="Genres" Hidden="@(Picker.IsColumnHidden("Genres", false))">
@foreach (var genre in context.Genres)
{
<Tag>@genre.Name</Tag>
}
</Column>
@if (FieldVisible(Field.KeysAllocated))
{
<Column TData="int" Title="@Field.KeysAllocated.GetDisplayName()">
@context.Keys?.Count(k => k.ClaimedOn.HasValue)
</Column>
}
@if (FieldVisible(Field.Developers))
{
<Column TData="string[]" Title="@Field.Developers.GetDisplayName()">
@foreach (var dev in context.Developers)
{
<Tag>@dev.Name</Tag>
}
</Column>
}
@if (FieldVisible(Field.Publishers))
{
<Column TData="string[]" Title="@Field.Publishers.GetDisplayName()">
@foreach (var pub in context.Publishers)
{
<Tag>@pub.Name</Tag>
}
</Column>
}
@if (FieldVisible(Field.Genres))
{
<Column TData="string[]" Title="@Field.Genres.GetDisplayName()">
@foreach (var genre in context.Genres)
{
<Tag>@genre.Name</Tag>
}
</Column>
}
@if (FieldVisible(Field.MultiplayerModes))
{
<Column TData="Data.Enums.MultiplayerType[]" Title="@Field.MultiplayerModes.GetDisplayName()">
@foreach (var mode in context.MultiplayerModes.Select(mm => mm.Type).Distinct())
{
<Tag>@mode.GetDisplayName()</Tag>
}
</Column>
}
@if (FieldVisible(Field.ArchiveSize))
{
long? compressedSize = context.Archives?.OrderByDescending(a => a.CreatedOn).FirstOrDefault()?.CompressedSize;
<Column TData="long" Title="@Field.ArchiveSize.GetDisplayName()">
@if (compressedSize.HasValue)
{
@ByteSizeLib.ByteSize.FromBytes((double)compressedSize)
}
</Column>
}
<Column TData="Data.Enums.MultiplayerType[]" Title="Multiplayer Modes" Hidden="@(Picker.IsColumnHidden("Multiplayer Modes"))">
@foreach (var mode in context.MultiplayerModes.Select(mm => mm.Type).Distinct())
{
<Tag>@mode.GetDisplayName()</Tag>
}
</Column>
<ActionColumn Title="" Style="text-align: right">
<TitleTemplate>
<div style="text-align: right">
<Button Icon="@IconType.Outline.Edit" Type="@ButtonType.Text" OnClick="() => OpenFieldPicker()" />
<Button Icon="@IconType.Outline.Edit" Type="@ButtonType.Text" OnClick="() => OpenColumnPicker()" />
</div>
</TitleTemplate>
<ChildContent>
@ -195,58 +114,17 @@
</ActionColumn>
</Table>
@code {
@code {
IEnumerable<Game> Games { get; set; } = new List<Game>();
bool Loading = true;
bool FieldPickerVisible = false;
string Search = "";
ITable Table;
bool Visibility = false;
Dictionary<Field, bool> FieldVisibility = new Dictionary<Field, bool>()
{
{ Field.Icon, true },
{ Field.Title, true },
{ Field.SortTitle, true },
{ Field.ReleasedOn, true },
{ Field.CreatedOn, true },
{ Field.CreatedBy, true },
{ Field.UpdatedOn, true },
{ Field.UpdatedBy, true }
};
enum Field
{
Icon,
Title,
[Display(Name = "Sort Title")]
SortTitle,
[Display(Name = "Released On")]
ReleasedOn,
[Display(Name = "Created On")]
CreatedOn,
[Display(Name = "Created By")]
CreatedBy,
[Display(Name = "Updated On")]
UpdatedOn,
[Display(Name = "Updated By")]
UpdatedBy,
Singleplayer,
Multiplayer,
[Display(Name = "Total Keys")]
TotalKeys,
[Display(Name = "Keys Allocated")]
KeysAllocated,
Developers,
Publishers,
Genres,
[Display(Name = "Multiplayer Modes")]
MultiplayerModes,
[Display(Name = "Archive Size")]
ArchiveSize,
}
TableColumnPicker Picker;
bool ColumnPickerVisible = false;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
@ -256,11 +134,6 @@
Loading = false;
var storedFieldVisibility = await BrowserStorage.GetAsync<Dictionary<Field, bool>>("Views.Games.FieldPicker");
if (storedFieldVisibility.Success && storedFieldVisibility.Value != null)
FieldVisibility = storedFieldVisibility.Value;
StateHasChanged();
}
}
@ -270,16 +143,6 @@
Games = await GameService.Get(g => g.Title.ToLower().Contains(Search.ToLower().Trim()) || g.SortTitle.ToLower().Contains(Search.ToLower().Trim())).OrderBy(g => String.IsNullOrWhiteSpace(g.SortTitle) ? g.Title : g.SortTitle).ToListAsync();
}
private bool FieldVisible(Field field)
{
return FieldVisibility.ContainsKey(field) && FieldVisibility[field] == true;
}
private void ChangeFieldVisibility(Field field, bool state)
{
FieldVisibility[field] = state;
}
private string GetIcon(Game game)
{
return $"/api/Games/{game.Id}/Icon.png";
@ -313,15 +176,13 @@
Loading = false;
}
private async Task OpenFieldPicker()
private async Task OpenColumnPicker()
{
FieldPickerVisible = true;
ColumnPickerVisible = true;
}
private async Task CloseFieldPicker()
private async Task CloseColumnPicker()
{
FieldPickerVisible = false;
await BrowserStorage.SetAsync("Views.Games.FieldPicker", FieldVisibility);
ColumnPickerVisible = false;
}
}

View File

@ -29,33 +29,42 @@
</PageHeaderExtra>
</PageHeader>
<Table TItem="Server" DataSource="@Servers" Loading="@Loading" PageSize="25" @bind-SelectedRows="SelectedServers">
<TableColumnPicker @ref="Picker" Key="Servers" @bind-Visible="ColumnPickerVisible" />
<Table TItem="Server" DataSource="@Servers" Loading="@Loading" PageSize="25" @bind-SelectedRows="SelectedServers" Responsive>
<Selection Key="@(context.Id.ToString())" />
<PropertyColumn Property="s => s.Name" Sortable />
<PropertyColumn Property="s => s.Game">
<PropertyColumn Property="s => s.Name" Sortable Hidden="@(Picker.IsColumnHidden("Name"))" />
<PropertyColumn Property="s => s.Game" Hidden="@(Picker.IsColumnHidden("Game"))">
<Image Src="@GetIcon(context.Game)" Height="32" Width="32" Preview="false"></Image>
@context.Game?.Title
</PropertyColumn>
<PropertyColumn Property="s => s.CreatedOn" Format="MM/dd/yyyy hh:mm tt" Sortable />
<PropertyColumn Property="s => s.CreatedBy" Sortable>
<PropertyColumn Property="s => s.CreatedOn" Format="MM/dd/yyyy hh:mm tt" Sortable Hidden="@(Picker.IsColumnHidden("Created On"))" />
<PropertyColumn Property="s => s.CreatedBy" Sortable Hidden="@(Picker.IsColumnHidden("Created By"))">
@context.CreatedBy?.UserName
</PropertyColumn>
<PropertyColumn Property="g => g.UpdatedOn" Format="MM/dd/yyyy hh:mm tt" Sortable />
<PropertyColumn Property="g => g.UpdatedBy" Sortable>
<PropertyColumn Property="g => g.UpdatedOn" Format="MM/dd/yyyy hh:mm tt" Sortable Hidden="@(Picker.IsColumnHidden("Updated On"))" />
<PropertyColumn Property="g => g.UpdatedBy" Sortable Hidden="@(Picker.IsColumnHidden("Updated By"))">
@context.UpdatedBy?.UserName
</PropertyColumn>
<ActionColumn Title="" Style="text-align: right">
<ServerControl ServerId="context.Id" />
<Space Direction="DirectionVHType.Horizontal">
<SpaceItem>
<Button OnClick="() => Edit(context)">Edit</Button>
</SpaceItem>
<SpaceItem>
<Popconfirm OnConfirm="() => Delete(context)" Title="Are you sure you want to delete this server?">
<Button Icon="@IconType.Outline.Close" Type="@ButtonType.Text" Danger />
</Popconfirm>
</SpaceItem>
</Space>
<TitleTemplate>
<div style="text-align: right">
<Button Icon="@IconType.Outline.Edit" Type="@ButtonType.Text" OnClick="() => OpenColumnPicker()" />
</div>
</TitleTemplate>
<ChildContent>
<ServerControl ServerId="context.Id" />
<Space Direction="DirectionVHType.Horizontal">
<SpaceItem>
<Button OnClick="() => Edit(context)">Edit</Button>
</SpaceItem>
<SpaceItem>
<Popconfirm OnConfirm="() => Delete(context)" Title="Are you sure you want to delete this server?">
<Button Icon="@IconType.Outline.Close" Type="@ButtonType.Text" Danger />
</Popconfirm>
</SpaceItem>
</Space>
</ChildContent>
</ActionColumn>
</Table>
@ -67,6 +76,8 @@
string Search = "";
IEnumerable<Server> SelectedServers;
TableColumnPicker Picker;
bool ColumnPickerVisible = false;
protected override void OnAfterRender(bool firstRender)
{
@ -140,4 +151,14 @@
ServerProcessService.StopServer(server);
}
}
private async Task OpenColumnPicker()
{
ColumnPickerVisible = true;
}
private async Task CloseColumnPicker()
{
ColumnPickerVisible = false;
}
}

View File

@ -12,4 +12,4 @@
@using LANCommander.Components
@using LANCommander.Shared
@using LANCommander.Services
@using LANCommander.Data.Models
@using LANCommander.Data.Models