Fix multi-log open race and debug log horizontal scrollbar#523
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Addresses two runtime regressions: a Fluxor effect ordering race when opening multiple Live logs back-to-back (leading to a briefly-populated then emptied table), and a Debug Log modal horizontal scrollbar regression for long lines.
Changes:
- Reordered
Effects.HandleCloseAllso LogTable/StatusBar close actions and in-memory cache clears occur before awaiting watcher teardown, preventingOpenLogActionfrom racing into stale/soon-to-be-cleared UI state. - Added a regression unit test that holds
RemoveAllAsync()viaTaskCompletionSourceto assert the synchronous “state-clearing prefix” happens before the awaited watcher drain. - Adjusted Debug Log modal rendering/CSS to clip long lines (no horizontal scrollbar) and added
titlemirroring for hover-to-see-full-text, with a new component test to pin the invariant.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Unit/EventLogExpert.UI.Tests/EventLog/EffectsTests.cs | Adds regression coverage for HandleCloseAll ordering; minor cleanup to filter test helper usage; relocates an existing XML-reload test. |
| tests/Unit/EventLogExpert.Components.Tests/Modals/DebugLogModalTests.cs | Adds regression test ensuring each rendered row mirrors its text into a title attribute. |
| src/EventLogExpert.UI/EventLog/Effects.cs | Moves dispatches and cache clears ahead of awaiting watcher removal to eliminate the close/open race. |
| src/EventLogExpert.Components/Modals/DebugLogModal.razor.css | Prevents horizontal scrollbar and applies clipping/ellipsis styling to long log rows. |
| src/EventLogExpert.Components/Modals/DebugLogModal.razor | Adds title="@line" to rows; minor attribute ordering/class ordering adjustments. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
NikTilton
approved these changes
May 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two unrelated runtime fixes off
main.Bugs
Root cause
CloseAll race
Commit
f046a07flippedEventLogExpertEffects.HandleCloseAll's_logWatcherService.RemoveAll()(sync) toRemoveAllAsync()(async). Pre-f046a07the entire effect body ran synchronously inside theDispatch(CloseAllAction)frame; post-f046a07the dispatches that follow the await race againstHandleOpenLog. Fluxor'sDispatchruns reducers synchronously and starts effects but does not await them. Callers (MauiMenuActionService.OpenLogAsync,SettingsModal.ReloadOpenLogs) dispatchCloseAllActionimmediately followed byOpenLogActionback-to-back synchronously. With Live then Live, a Channel watcher is registered,RemoveAllAsyncreturns a non-completed Task, the await yields,HandleOpenLogpopulates the table viaAddTableAction+UpdateTableAction, and the continuation then dispatchesLogTable.CloseAllActionwhich wipes the freshly populated table.Debug log scrollbar
.debug-log-viewport { overflow-x: auto }combined with.debug-log-row { white-space: pre }on long lines (e.g., long stack traces or paths) re-introduced the horizontal scrollbar.Fix
HandleCloseAll: dispatchLogTable.CloseAllAction/StatusBar.CloseAllActionand clear all in-memory bookkeeping (_resolverCache,_xmlResolver,_logsLoadedWithXml,_pendingSelectionRestore) BEFORE awaiting_logWatcherService.RemoveAllAsync(). The watcher drain is pure resource cleanup and does not read these caches, so flushing them up front is safe and ensures any caller-dispatchedOpenLogActionruns against cleared state.HandleCloseAll_DispatchesStateClearsBeforeWatcherDrainuses aTaskCompletionSourceto holdRemoveAllAsyncand asserts every state-clearing call already happened during the synchronous prefix.overflow-x: hidden; rows getwidth: 100%,overflow: hidden,text-overflow: ellipsis(keptwhite-space: preso leading indentation in stack traces still reads correctly). Each row gains atitle="@line"attribute so users can hover to read the full clipped content as a native browser tooltip.DebugLogModal_AfterLoad_RowsCarryTitleAttributeMirroringTextpins the title-mirror invariant.Verified
dotnet build EventLogExpert.slnx: 0 warnings / 0 errors.dotnet format whitespace --verify-no-changes: clean.dotnet format style --verify-no-changes --diagnostics IDE0005 IDE0065: clean.dotnet test EventLogExpert.slnx --no-build: 1853 passed / 2 skipped / 0 failed across all 7 test projects.