@page "/Games/{id:guid}/Redistributables" @using LANCommander.SDK.Enums @using LANCommander.Server.UI.Pages.Games.Components @using YamlDotNet.Serialization @using YamlDotNet.Serialization.NamingConventions @attribute [Authorize(Roles = RoleService.AdministratorRoleName)] @inject GameService GameService @inject RedistributableService RedistributableService @inject ModalService ModalService @inject IMessageService MessageService @inject ILogger Logger Redistributables @if (_loaded) { @if (!_gameRedistributables.Any()) { } @foreach (var redist in _gameRedistributables) { } @code { [Parameter] public Guid Id { get; set; } GameEditView EditView; bool _loaded; List _gameRedistributables = new(); List _allRedistributables = new(); Dictionary> _redistOptions = new(); protected override async Task OnParametersSetAsync() { if (!_loaded && Id != Guid.Empty) await LoadData(); } async Task LoadData() { _allRedistributables = (await RedistributableService.GetAsync()).ToList(); var game = await GameService .AsNoTracking() .Include(g => g.Redistributables) .GetAsync(Id); if (game?.Redistributables != null) { _gameRedistributables = game.Redistributables.ToList(); foreach (var redist in _gameRedistributables.Where(r => !string.IsNullOrWhiteSpace(r.OptionSchema))) { var optionsJson = await GameService.GetRedistributableOptionsAsync(Id, redist.Id); if (!string.IsNullOrWhiteSpace(optionsJson)) { try { _redistOptions[redist.Id] = System.Text.Json.JsonSerializer.Deserialize>(optionsJson); } catch { } } } } _loaded = true; } async Task OpenAddRedistributableDialog() { var available = _allRedistributables .Where(r => !_gameRedistributables.Any(gr => gr.Id == r.Id)) .ToList(); if (!available.Any()) { MessageService.Info("All redistributables have already been added."); return; } var modalOptions = new ModalOptions { Title = "Add Redistributable", Maximizable = false, Closable = true, OkText = "Add", }; var modalRef = await ModalService.CreateModalAsync, Redistributable>(modalOptions, available); modalRef.OnOk = async (selected) => { if (selected != null) { _gameRedistributables.Add(selected); await SyncRedistributables(); StateHasChanged(); } }; } async Task RemoveRedistributable(Redistributable redist) { _gameRedistributables.Remove(redist); _redistOptions.Remove(redist.Id); await SyncRedistributables(); } async Task SyncRedistributables() { var game = await GameService .Include(g => g.Redistributables) .GetAsync(Id); game.Redistributables = _gameRedistributables; await GameService.UpdateAsync(game); } void OnOptionChanged((Guid redistId, string optionName, string value) args) { if (!_redistOptions.ContainsKey(args.redistId)) _redistOptions[args.redistId] = new Dictionary(); _redistOptions[args.redistId][args.optionName] = args.value; } async Task Save() { try { foreach (var kvp in _redistOptions) { var optionsJson = System.Text.Json.JsonSerializer.Serialize(kvp.Value); await GameService.SetRedistributableOptionsAsync(Id, kvp.Key, optionsJson); } MessageService.Success("Redistributable options saved!"); } catch (Exception ex) { MessageService.Error("Could not save redistributable options!"); Logger.LogError(ex, "Could not save redistributable options!"); } } SDK.Models.OptionSchema ParseOptionSchema(string yaml) { if (string.IsNullOrWhiteSpace(yaml)) return null; try { var deserializer = new DeserializerBuilder() .WithNamingConvention(PascalCaseNamingConvention.Instance) .WithTypeConverter(new SDK.Models.OptionChoiceYamlConverter()) .IgnoreUnmatchedProperties() .Build(); return deserializer.Deserialize(yaml); } catch { return null; } } }