Adding a game now immediately provides a dialog to lookup a game through metadata providers. Selecting a result will create the game with the populated metadata. An additional option of automatically downloading art (icon, cover, background, logo) is also provided, though may be inaccurate and completely up to the results of the provider.
253 lines
8.3 KiB
Text
253 lines
8.3 KiB
Text
@page "/Games"
|
|
@using SortDirection = AntDesign.SortDirection
|
|
@using AntDesign.TableModels
|
|
@attribute [Authorize]
|
|
@inject GameService GameService
|
|
@inject MetadataService MetadataService
|
|
@inject NavigationManager NavigationManager
|
|
@inject ModalService ModalService
|
|
@inject IMessageService MessageService
|
|
@inject ILogger<Index> Logger
|
|
|
|
<PageHeader Title="Games" Subtitle="@Total.ToString()" />
|
|
|
|
<DataTable
|
|
@ref="Table"
|
|
TItem="Game"
|
|
@bind-SelectedRows="Selected"
|
|
@bind-Total="Total"
|
|
Size="@TableSize.Small"
|
|
Responsive
|
|
ColumnPicker
|
|
Searchable
|
|
SearchProperty="g => g.Title"
|
|
Children="(g, dg) => dg.BaseGameId == g.Id && (dg.Type == GameType.Expansion || dg.Type == GameType.Mod)"
|
|
Query="g => g.BaseGameId == null || g.BaseGameId == Guid.Empty || (g.Type != GameType.Expansion && g.Type != GameType.Mod)">
|
|
<RightToolbar>
|
|
@if (Selected != null && Selected.Count() > 0)
|
|
{
|
|
<Button OnClick="() => AddToCollection()" Type="@ButtonType.Default">Add to Collection</Button>
|
|
}
|
|
<Button Type="@ButtonType.Default" OnClick="OpenImportDialog">Import</Button>
|
|
<Button OnClick="() => Add()" Type="@ButtonType.Primary">Add Game</Button>
|
|
</RightToolbar>
|
|
<Columns>
|
|
<Selection Key="@(context.Id.ToString())" CheckStrictly="true" />
|
|
|
|
<DataColumn TData="string" Title="Icon" Include="Media">
|
|
<Image Src="@GetIcon(context)" Height="32" Width="32" Preview="false"></Image>
|
|
</DataColumn>
|
|
|
|
<BoundDataColumn Property="g => g.Title" Sortable DefaultSortOrder="SortDirection.Ascending" />
|
|
|
|
<BoundDataColumn Property="g => g.MultiplayerModes" Include="MultiplayerModes" Sortable Title="Multiplayer">
|
|
<Checkbox Disabled="true" Checked="context.MultiplayerModes?.Count > 0" />
|
|
</BoundDataColumn>
|
|
|
|
<BoundDataColumn Property="g => g.Keys" Title="Total Keys" Include="Keys" Sortable>
|
|
@context.Keys?.Count
|
|
</BoundDataColumn>
|
|
<BoundDataColumn Property="g => g.Keys" Title="Keys Allocated" Include="Keys" Sortable>
|
|
@context.Keys?.Count(k => k.ClaimedOn.HasValue)
|
|
</BoundDataColumn>
|
|
|
|
<DataColumn TData="string[]" Title="Collections" Include="Collections">
|
|
@if (context.Collections != null)
|
|
foreach (var collection in context.Collections)
|
|
{
|
|
<Tag>@collection.Name</Tag>
|
|
}
|
|
</DataColumn>
|
|
|
|
<DataColumn TData="string[]" Title="Developers" Include="Developers" Hide>
|
|
@if (context.Developers != null)
|
|
foreach (var dev in context.Developers)
|
|
{
|
|
<Tag>@dev.Name</Tag>
|
|
}
|
|
</DataColumn>
|
|
|
|
<DataColumn TData="string[]" Title="Publishers" Include="Publishers" Hide>
|
|
@if (context.Publishers != null)
|
|
foreach (var pub in context.Publishers)
|
|
{
|
|
<Tag>@pub.Name</Tag>
|
|
}
|
|
</DataColumn>
|
|
|
|
<DataColumn TData="string[]" Title="Genres" Include="Genres" Hide>
|
|
@if (context.Genres != null)
|
|
foreach (var genre in context.Genres)
|
|
{
|
|
<Tag>@genre.Name</Tag>
|
|
}
|
|
</DataColumn>
|
|
|
|
<DataColumn TData="string[]" Title="Platforms" Include="Platforms" Hide>
|
|
@if (context.Platforms != null)
|
|
foreach (var platform in context.Platforms)
|
|
{
|
|
<Tag>@platform.Name</Tag>
|
|
}
|
|
</DataColumn>
|
|
|
|
<DataColumn TData="SDK.Enums.MultiplayerType[]" Title="Multiplayer Modes" Include="MultiplayerModes" Hide>
|
|
@if (context.MultiplayerModes != null)
|
|
foreach (var mode in context.MultiplayerModes.Select(mm => mm.Type).Distinct())
|
|
{
|
|
<Tag>@mode.GetDisplayName()</Tag>
|
|
}
|
|
</DataColumn>
|
|
|
|
<BoundDataColumn Property="g => g.CreatedOn" Title="Created On" Sortable>
|
|
<LocalTime Value="context.CreatedOn" />
|
|
</BoundDataColumn>
|
|
|
|
<BoundDataColumn Property="g => g.UpdatedOn" Title="Updated On" Sortable>
|
|
<LocalTime Value="context.UpdatedOn" />
|
|
</BoundDataColumn>
|
|
|
|
<BoundDataColumn Property="g => g.CreatedBy" Sortable Title="Created By" Include="CreatedBy">
|
|
@context.CreatedBy?.UserName
|
|
</BoundDataColumn>
|
|
|
|
<BoundDataColumn Property="g => g.UpdatedBy" Title="Updated By" Sortable Include="UpdatedBy">
|
|
@context.UpdatedBy?.UserName
|
|
</BoundDataColumn>
|
|
|
|
<DataActions TData="string">
|
|
<Flex Gap="FlexGap.Small" Align="FlexAlign.Center" Justify="FlexJustify.End">
|
|
<a href="@($"/Games/{context.Id}")" class="ant-btn ant-btn-primary">Edit</a>
|
|
<Popconfirm OnConfirm="() => Delete(context)" Title="Are you sure you want to delete this game?">
|
|
<Button Icon="@IconType.Outline.Close" Type="@ButtonType.Text" Danger/>
|
|
</Popconfirm>
|
|
</Flex>
|
|
</DataActions>
|
|
</Columns>
|
|
|
|
<PaginationTemplate>
|
|
<Pagination
|
|
Total="context.Total"
|
|
PageSize="context.PageSize"
|
|
Current="context.PageIndex"
|
|
DefaultPageSize="25"
|
|
PageSizeOptions="new [] { 25, 50, 100, 200 }"
|
|
ShowSizeChanger
|
|
OnChange="context.HandlePageChange" />
|
|
</PaginationTemplate>
|
|
</DataTable>
|
|
|
|
@code {
|
|
bool Visibility = false;
|
|
|
|
IEnumerable<Game> Selected;
|
|
int Total;
|
|
|
|
DataTable<Game> Table;
|
|
|
|
string GetIcon(Game game)
|
|
{
|
|
var media = game?.Media?.FirstOrDefault(m => m.Type == SDK.Enums.MediaType.Icon);
|
|
|
|
if (media != null)
|
|
return $"/api/Media/{media.Id}/Download?fileId={media.FileId}";
|
|
else
|
|
return "/favicon.ico";
|
|
}
|
|
|
|
bool _hasMetadataProviders;
|
|
|
|
protected override void OnInitialized()
|
|
{
|
|
_hasMetadataProviders = MetadataService.GetProviderNames().Any();
|
|
}
|
|
|
|
async Task Add()
|
|
{
|
|
if (_hasMetadataProviders)
|
|
{
|
|
var modalOptions = new ModalOptions
|
|
{
|
|
Title = "Add Game",
|
|
Maximizable = false,
|
|
DefaultMaximized = false,
|
|
Closable = true,
|
|
Footer = null,
|
|
};
|
|
|
|
var modalRef = ModalService.CreateModal<AddGameDialog, AddGameDialogOptions>(modalOptions, new AddGameDialogOptions());
|
|
modalRef.OnClose = Reload;
|
|
}
|
|
else
|
|
{
|
|
NavigationManager.NavigateTo("/Games/Add");
|
|
}
|
|
}
|
|
|
|
async Task Delete(Game game)
|
|
{
|
|
try
|
|
{
|
|
await GameService.DeleteAsync(game);
|
|
|
|
MessageService.Success($"{game.Title} was successfully deleted!");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageService.Error("Could not delete the game!");
|
|
Logger.LogError(ex, "Could not delete the game!");
|
|
}
|
|
|
|
await Reload();
|
|
}
|
|
|
|
async void AddToCollection()
|
|
{
|
|
var modalOptions = new ModalOptions()
|
|
{
|
|
Title = "Add to Collection",
|
|
Maximizable = false,
|
|
DefaultMaximized = false,
|
|
Closable = true,
|
|
OkText = "Add"
|
|
};
|
|
|
|
var options = new AddToCollectionOptions()
|
|
{
|
|
GameIds = Selected.Select(g => g.Id)
|
|
};
|
|
|
|
var modalRef = await ModalService.CreateModalAsync<AddToCollectionDialog, AddToCollectionOptions, IEnumerable<Collection>>(modalOptions, options);
|
|
|
|
modalRef.OnOk = async (collections) =>
|
|
{
|
|
Table.UnselectAll();
|
|
await Reload();
|
|
};
|
|
}
|
|
|
|
async Task OpenImportDialog()
|
|
{
|
|
var options = new ImportDialogOptions
|
|
{
|
|
Hint = "Only LCX files are supported for importing games",
|
|
ManifestType = ManifestType.Game,
|
|
};
|
|
|
|
var modalOptions = new ModalOptions
|
|
{
|
|
Title = "Import Game",
|
|
DestroyOnClose = true,
|
|
MaskClosable = false,
|
|
Footer = null,
|
|
};
|
|
|
|
var modalRef = ModalService.CreateModal<ImportUploadDialog, ImportDialogOptions>(modalOptions, options);
|
|
modalRef.OnOk = modalRef.OnCancel = modalRef.OnClose = Reload;
|
|
}
|
|
|
|
async Task Reload()
|
|
{
|
|
await Table.ReloadAsync();
|
|
}
|
|
}
|