From 3b6c7a22346240651e0dffe28f5d45f1cb6eac38 Mon Sep 17 00:00:00 2001 From: beo3000 Date: Fri, 9 Jan 2026 13:29:37 +0100 Subject: [PATCH] fix ui deadlock problem --- docs/development_guidelines.md | 5 ++++ .../Game/DeathBox/DeathBoxBoard.razor | 13 +++++++---- .../Pages/Admin/GifManagement.razor | 23 ++++++++++++++++--- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/docs/development_guidelines.md b/docs/development_guidelines.md index 9bc734e..347dab2 100644 --- a/docs/development_guidelines.md +++ b/docs/development_guidelines.md @@ -92,6 +92,11 @@ Break complex work into 3-5 stages. Document in `IMPLEMENTATION_PLAN.md` see [do - Handle errors at appropriate level - Never silently swallow exceptions +Be aware of critical patterns, that can lead to deadlocks or other problem when using async methods. E.G.: +- Search(pattern: "@\(_.*\.Result\)", glob: "*.razor", output_mode: "content") +- Search(pattern: "\)\.Result", glob: "*.razor", output_mode: "content") +- Search(pattern: "\.Wait\(\)", glob: "*.razor", output_mode: "content") + ## Decision Framework When multiple valid approaches exist, choose based on: diff --git a/src/Koogle.Web/Components/Game/DeathBox/DeathBoxBoard.razor b/src/Koogle.Web/Components/Game/DeathBox/DeathBoxBoard.razor index 3fd061c..5917d88 100644 --- a/src/Koogle.Web/Components/Game/DeathBox/DeathBoxBoard.razor +++ b/src/Koogle.Web/Components/Game/DeathBox/DeathBoxBoard.razor @@ -46,7 +46,7 @@ @if (_model.LastThrow != null) { - @(_ = GetLastThrowMessage().Result) + @_lastThrowMessage } @@ -172,18 +172,21 @@ private DeathBoxGameModel? _model; private List _playerStats = []; private int _activePlayerCount = 0; + private string _lastThrowMessage = ""; - protected override void OnInitialized() + protected override async Task OnInitializedAsync() { - base.OnInitialized(); + await base.OnInitializedAsync(); GameState.StateChanged += OnGameStateChanged; UpdateStats(); + _lastThrowMessage = await GetLastThrowMessage(); } - private void OnGameStateChanged(object? sender, EventArgs e) + private async void OnGameStateChanged(object? sender, EventArgs e) { UpdateStats(); - InvokeAsync(StateHasChanged); + _lastThrowMessage = await GetLastThrowMessage(); + await InvokeAsync(StateHasChanged); } private void UpdateStats() diff --git a/src/Koogle.Web/Components/Pages/Admin/GifManagement.razor b/src/Koogle.Web/Components/Pages/Admin/GifManagement.razor index 4a62ac6..c2978c9 100644 --- a/src/Koogle.Web/Components/Pages/Admin/GifManagement.razor +++ b/src/Koogle.Web/Components/Pages/Admin/GifManagement.razor @@ -63,13 +63,14 @@ + @if (context.ContentType.StartsWith("image/")) { - + } else { - + } @@ -80,7 +81,7 @@ @foreach (var evt in GetAssignedEvents(context.AssignedEvents)) { - @(_ = Term.GetThrowEventName(evt).Result) + @GetEventName(evt) } @@ -245,6 +246,7 @@ private bool _isLoading = true; private string? _error; private int _pendingCount => _gifs.Count(g => g.IsPendingApproval); + private Dictionary _eventNames = new(); protected override async Task OnInitializedAsync() { @@ -259,6 +261,7 @@ var clubId = ClubContext.ClubId; _gifs = (await GifService.GetByClubAsync(clubId, includePending: true)).ToList(); _tokens = (await GifService.GetSubmissionTokensByClubAsync(clubId)).ToList(); + await LoadEventNames(); } catch (Exception ex) { @@ -267,6 +270,17 @@ finally { _isLoading = false; + StateHasChanged(); + } + } + + private async Task LoadEventNames() + { + var eventTypes = new[] { ThrowEventType.Strike, ThrowEventType.Circle, ThrowEventType.Bell, + ThrowEventType.Gutter, ThrowEventType.NoWood, ThrowEventType.Cleared }; + foreach (var evt in eventTypes) + { + _eventNames[evt] = await Term.GetThrowEventName(evt); } } @@ -516,6 +530,9 @@ return result; } + private string GetEventName(ThrowEventType type) => + _eventNames.TryGetValue(type, out var name) ? name : type.ToString(); + private static Color GetEventColor(ThrowEventType type) => type switch { ThrowEventType.Strike => Color.Success,