321 lines
12 KiB
Text
321 lines
12 KiB
Text
@page "/Games/{id:guid}/General"
|
|
@page "/Games/{id:guid}"
|
|
@page "/Games/Add"
|
|
@attribute [Authorize(Roles = RoleService.AdministratorRoleName)]
|
|
@using PSC.Blazor.Components.MarkdownEditor
|
|
@using PSC.Blazor.Components.MarkdownEditor.Models
|
|
@inject CollectionService CollectionService
|
|
@inject CompanyService CompanyService
|
|
@inject EngineService EngineService
|
|
@inject GameService GameService
|
|
@inject GenreService GenreService
|
|
@inject PlatformService PlatformService
|
|
@inject TagService TagService
|
|
@inject IMessageService MessageService
|
|
@inject ModalService ModalService
|
|
@inject NavigationManager NavigationManager
|
|
@inject ILogger<General> Logger
|
|
|
|
<GameEditView Id="Id">
|
|
<TitleTemplate>
|
|
@if (context.Id == Guid.Empty)
|
|
{
|
|
<Text>Add New Game</Text>
|
|
}
|
|
else
|
|
{
|
|
<Text>General</Text>
|
|
}
|
|
</TitleTemplate>
|
|
<TitleExtraTemplate>
|
|
<Flex Gap="FlexGap.Small" Justify="FlexJustify.End">
|
|
@if (context != null && context.Id != Guid.Empty)
|
|
{
|
|
<Button OnClick="OpenExportDialog" Loading="_openingExportDialog">Export</Button>
|
|
}
|
|
|
|
<Button Type="ButtonType.Primary" OnClick="() => Save(context)">Save</Button>
|
|
</Flex>
|
|
</TitleExtraTemplate>
|
|
|
|
<ChildContent>
|
|
<Form
|
|
@ref="_form"
|
|
Model="@context"
|
|
Layout="@FormLayout.Vertical"
|
|
Context="formContext">
|
|
<FormItem Label="Title">
|
|
<GameMetadataLookup
|
|
ButtonText="Lookup"
|
|
AutoFocus="context.Id == Guid.Empty"
|
|
@bind-Value="context.Title"
|
|
GameId="@context.Id"
|
|
OnImported="OnGameImported" />
|
|
</FormItem>
|
|
<FormItem Label="Sort Title">
|
|
<Input @bind-Value="@context.SortTitle" />
|
|
</FormItem>
|
|
<FormItem Label="Notes">
|
|
<TextArea @bind-Value="@context.Notes" MaxLength=2000 ShowCount />
|
|
</FormItem>
|
|
<FormItem Label="Description">
|
|
<MarkdownEditor
|
|
@bind-Value="context.Description"
|
|
SpellChecker="false"
|
|
CSSClass="ant-typography"
|
|
MinHeight="500px" />
|
|
</FormItem>
|
|
<FormItem Label="Engine">
|
|
<Select TItem="Engine"
|
|
TItemValue="Guid?"
|
|
DataSource="@Engines.OrderBy(e => e.Name)"
|
|
@bind-Value="@context.EngineId"
|
|
LabelName="Name"
|
|
ValueName="Id"
|
|
Placeholder="Select an Engine"
|
|
DefaultActiveFirstOption="false"
|
|
EnableSearch />
|
|
</FormItem>
|
|
<FormItem Label="Type">
|
|
<Select @bind-Value="@context.Type" TItem="GameType" TItemValue="GameType" DataSource="Enum.GetValues<GameType>()">
|
|
<LabelTemplate Context="Value">@Value.GetDisplayName()</LabelTemplate>
|
|
<ItemTemplate Context="Value">@Value.GetDisplayName()</ItemTemplate>
|
|
</Select>
|
|
</FormItem>
|
|
@if (context.Type != GameType.MainGame)
|
|
{
|
|
<FormItem Label="Base Game" Rules="@(new[] { new FormValidationRule { Required = true } })">
|
|
<Flex Gap="FlexGap.Small" Wrap="FlexWrap.NoWrap">
|
|
<Select TItem="Game"
|
|
TItemValue="Guid?"
|
|
DataSource="@Games.Where(g => g.Id != context.Id).OrderBy(g => String.IsNullOrWhiteSpace(g.SortTitle) ? g.Title : g.SortTitle)"
|
|
@bind-Value="@context.BaseGameId"
|
|
LabelName="Title"
|
|
ValueName="Id"
|
|
Placeholder="Select a Game"
|
|
DefaultActiveFirstOption="false"
|
|
EnableSearch>
|
|
<ItemTemplate Context="baseGame">
|
|
<Image Src="@GetIcon(baseGame)" Height="32" Width="32" Preview="false"></Image>
|
|
@baseGame.Title
|
|
</ItemTemplate>
|
|
</Select>
|
|
|
|
@if (context.BaseGameId == null || context.BaseGameId == Guid.Empty)
|
|
{
|
|
<Button Type="ButtonType.Primary" Disabled>Edit</Button>
|
|
}
|
|
else
|
|
{
|
|
<a href="@($"/Games/{context.BaseGameId}")" class="ant-btn ant-btn-primary" target="_blank">Edit</a>
|
|
}
|
|
</Flex>
|
|
</FormItem>
|
|
}
|
|
<FormItem Label="Key Allocation Method">
|
|
<Select @bind-Value="@context.KeyAllocationMethod" TItem="KeyAllocationMethod" TItemValue="KeyAllocationMethod" DataSource="Enum.GetValues<KeyAllocationMethod>()">
|
|
<LabelTemplate Context="Value">@Value.GetDisplayName()</LabelTemplate>
|
|
<ItemTemplate Context="Value">@Value.GetDisplayName()</ItemTemplate>
|
|
</Select>
|
|
</FormItem>
|
|
<FormItem Label="Released On">
|
|
<DatePicker TValue="DateTime?" @bind-Value="@context.ReleasedOn" Picker="@DatePickerType.Date" />
|
|
</FormItem>
|
|
<FormItem Label="Singleplayer">
|
|
<Checkbox @bind-Checked="@context.Singleplayer" />
|
|
</FormItem>
|
|
<FormItem Label="External IDs">
|
|
<Space Direction="SpaceDirection.Vertical" Style="width: 100%">
|
|
@if (context.ExternalIds != null)
|
|
{
|
|
@foreach (var externalId in context.ExternalIds.ToList())
|
|
{
|
|
<SpaceItem>
|
|
<Flex Gap="FlexGap.Small">
|
|
<Input @bind-Value="@externalId.Provider" Placeholder="Provider (e.g. Steam, GOG, IGDB)" Style="width: 200px" />
|
|
<Input @bind-Value="@externalId.ExternalId" Placeholder="ID" Style="flex: 1" />
|
|
<Button Type="ButtonType.Text" Danger OnClick="() => RemoveExternalId(context, externalId)" Icon="@IconType.Outline.Close" />
|
|
</Flex>
|
|
</SpaceItem>
|
|
}
|
|
}
|
|
<SpaceItem>
|
|
<Flex Justify="FlexJustify.End">
|
|
<Button Type="ButtonType.Primary" OnClick="() => AddExternalId(context)">Add</Button>
|
|
</Flex>
|
|
</SpaceItem>
|
|
</Space>
|
|
</FormItem>
|
|
<FormItem Label="Developers">
|
|
<TaxonomyInput DataService="CompanyService" @bind-Values="context.Developers" />
|
|
</FormItem>
|
|
<FormItem Label="Publishers">
|
|
<TaxonomyInput DataService="CompanyService" @bind-Values="context.Publishers" />
|
|
</FormItem>
|
|
<FormItem Label="Platforms">
|
|
<TaxonomyInput DataService="PlatformService" @bind-Values="context.Platforms" />
|
|
</FormItem>
|
|
<FormItem Label="Genres">
|
|
<TaxonomyInput DataService="GenreService" @bind-Values="context.Genres" />
|
|
</FormItem>
|
|
<FormItem Label="Tags">
|
|
<TaxonomyInput DataService="TagService" @bind-Values="context.Tags" />
|
|
</FormItem>
|
|
<FormItem Label="Collections">
|
|
<TaxonomyInput DataService="CollectionService" @bind-Values="context.Collections" />
|
|
</FormItem>
|
|
</Form>
|
|
</ChildContent>
|
|
</GameEditView>
|
|
|
|
@code {
|
|
[Parameter] public Guid Id { get; set; }
|
|
|
|
bool _loaded;
|
|
bool _success;
|
|
bool _openingExportDialog;
|
|
|
|
IEnumerable<Engine> Engines = new List<Engine>();
|
|
IEnumerable<Game> Games = new List<Game>();
|
|
|
|
private GameMetadataLookup? GameMetadataLookup;
|
|
|
|
Form<Game> _form;
|
|
|
|
protected override async Task OnParametersSetAsync()
|
|
{
|
|
if (!_loaded)
|
|
await LoadData();
|
|
}
|
|
|
|
private async Task LoadData()
|
|
{
|
|
var allowedTypes = new List<GameType> { GameType.MainGame, GameType.StandaloneExpansion, GameType.StandaloneMod };
|
|
|
|
Engines = await EngineService.SortBy(g => g.Name).GetAsync();
|
|
Games = (await GameService
|
|
.Include(g => g.Media.Where(m => m.Type == MediaType.Icon))
|
|
.GetAsync(g => allowedTypes.Contains(g.Type)))
|
|
.OrderByTitle(g => String.IsNullOrWhiteSpace(g.SortTitle) ? g.Title : g.SortTitle);
|
|
|
|
_loaded = true;
|
|
}
|
|
|
|
private async Task Save(Game game)
|
|
{
|
|
try
|
|
{
|
|
if (_form.Validate())
|
|
{
|
|
if (game.Id != Guid.Empty)
|
|
{
|
|
game.BaseGame = null; // clearing base game, model setup will write the BaseGameId value, referenced model will be loaded on update/get
|
|
game = await GameService.UpdateAsync(game);
|
|
|
|
|
|
await MessageService.SuccessAsync("Game updated!");
|
|
}
|
|
else
|
|
{
|
|
game = await GameService.AddAsync(game);
|
|
|
|
NavigationManager.LocationChanged += NotifyGameAdded;
|
|
|
|
NavigationManager.NavigateTo($"/Games/{game.Id}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MessageService.Error("Could not save! Check fields and try again");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageService.Error("Could not save game!");
|
|
Logger.LogError(ex, "Could not save game!");
|
|
}
|
|
}
|
|
|
|
private void NotifyGameAdded(object? sender, LocationChangedEventArgs e)
|
|
{
|
|
NavigationManager.LocationChanged -= NotifyGameAdded;
|
|
|
|
MessageService.Success("Game added!");
|
|
}
|
|
|
|
private void OnGameImported(Guid gameId)
|
|
{
|
|
NavigationManager.NavigateTo($"/Games/{gameId}");
|
|
}
|
|
|
|
private 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";
|
|
}
|
|
|
|
private void AddExternalId(Game game)
|
|
{
|
|
game.ExternalIds ??= new List<GameExternalId>();
|
|
game.ExternalIds.Add(new GameExternalId());
|
|
}
|
|
|
|
private void RemoveExternalId(Game game, GameExternalId externalId)
|
|
{
|
|
game.ExternalIds?.Remove(externalId);
|
|
}
|
|
|
|
|
|
private async Task Delete(Game game)
|
|
{
|
|
Games = new List<Game>();
|
|
|
|
try
|
|
{
|
|
await GameService.DeleteAsync(game);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageService.Error($"Could not delete the {game.Type.GetDisplayName().ToLower()}!");
|
|
Logger.LogError(ex, $"Could not delete the {game.Type.GetDisplayName().ToLower()}!");
|
|
}
|
|
}
|
|
|
|
private async Task OpenExportDialog()
|
|
{
|
|
_openingExportDialog = true;
|
|
|
|
await InvokeAsync(StateHasChanged);
|
|
await Task.Yield();
|
|
|
|
var game = await GameService.GetAsync(Id);
|
|
|
|
var modalOptions = new ModalOptions()
|
|
{
|
|
Title = $"Export {game.Title}",
|
|
Maximizable = false,
|
|
DefaultMaximized = false,
|
|
Closable = true,
|
|
OkText = "Add",
|
|
Footer = null,
|
|
};
|
|
|
|
var options = new ExportDialogOptions()
|
|
{
|
|
RecordId = Id,
|
|
RecordType = ImportExportRecordType.Game
|
|
};
|
|
|
|
var modalRef = await ModalService.CreateModalAsync<ExportDialog, ExportDialogOptions>(modalOptions, options);
|
|
|
|
_openingExportDialog = false;
|
|
|
|
await InvokeAsync(StateHasChanged);
|
|
await Task.Yield();
|
|
}
|
|
|
|
}
|