PR U-6a: MainLayout wraps @Body in an ErrorBoundary
Add a Blazor built-in ErrorBoundary around @Body with a friendly FluentMessageBar + retry / home buttons. Also hook NavigationManager.LocationChanged so the boundary resets on any nav (otherwise the error state persists across NavigateTo and "Zur Startseite" still shows the failure banner). U-6 split into U-6a (this) and U-6b (per-handler try/catch to route expected exceptions to IMessageService — deferred). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
58ca05f83e
commit
562338d0c4
2 changed files with 42 additions and 3 deletions
|
|
@ -1,4 +1,6 @@
|
|||
@inherits LayoutComponentBase
|
||||
@inject NavigationManager Navigation
|
||||
@implements IDisposable
|
||||
|
||||
<FluentLayout>
|
||||
<FluentHeader Class="hidePrint">
|
||||
|
|
@ -9,7 +11,24 @@
|
|||
<FluentBodyContent Class="body-content">
|
||||
<FluentMessageBarProvider Section="MESSAGES_TOP" @rendermode="InteractiveServer" />
|
||||
<div class="content">
|
||||
@Body
|
||||
<ErrorBoundary @ref="errorBoundary">
|
||||
<ChildContent>
|
||||
@Body
|
||||
</ChildContent>
|
||||
<ErrorContent>
|
||||
<FluentStack Orientation="Orientation.Vertical" Style="padding: 2rem; max-width: 640px;">
|
||||
<FluentMessageBar Intent="MessageIntent.Error"
|
||||
Title="Ein Fehler ist aufgetreten"
|
||||
AllowDismiss="false">
|
||||
Diese Seite konnte nicht angezeigt werden. Details stehen im Server-Log.
|
||||
</FluentMessageBar>
|
||||
<FluentStack Orientation="Orientation.Horizontal">
|
||||
<FluentButton Appearance="Appearance.Neutral" OnClick="Recover">Neu versuchen</FluentButton>
|
||||
<FluentAnchor Href="/" Appearance="Appearance.Neutral">Zur Startseite</FluentAnchor>
|
||||
</FluentStack>
|
||||
</FluentStack>
|
||||
</ErrorContent>
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
</FluentBodyContent>
|
||||
</FluentStack>
|
||||
|
|
@ -28,4 +47,23 @@
|
|||
An unhandled error has occurred.
|
||||
<a href="." class="reload">Reload</a>
|
||||
<span class="dismiss">🗙</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private ErrorBoundary? errorBoundary;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
// ErrorBoundary state persists across NavigationManager.NavigateTo, so the
|
||||
// error page would linger even after the user clicked "Zur Startseite".
|
||||
// Reset on any location change.
|
||||
Navigation.LocationChanged += OnLocationChanged;
|
||||
}
|
||||
|
||||
private void OnLocationChanged(object? sender, Microsoft.AspNetCore.Components.Routing.LocationChangedEventArgs e)
|
||||
=> errorBoundary?.Recover();
|
||||
|
||||
private void Recover() => errorBoundary?.Recover();
|
||||
|
||||
public void Dispose() => Navigation.LocationChanged -= OnLocationChanged;
|
||||
}
|
||||
|
|
@ -165,7 +165,8 @@ Split into two PRs on delivery because the header path touches ~15 pages.
|
|||
### Phase 3 — Loading and error UX consistency
|
||||
|
||||
- **U-5** Shared `<LoadingWhen Data="@x">` component with a consistent skeleton visual. Adopt across every page currently using ad-hoc `@if (x is null) { <p>Lädt…</p> return; }`.
|
||||
- **U-6** Wrap each page (or the layout's `@Body`) in `<ErrorBoundary>` with a friendly retry UI. Route `SaveTransactionAsync` / `DeleteAccountAsync` etc. exceptions to `IMessageService` instead of bubbling.
|
||||
- **U-6a** Wrap `MainLayout`'s `@Body` in `<ErrorBoundary>` with a friendly retry UI. Reset on any `NavigationManager.LocationChanged` so the error state doesn't stick after the user clicks "Zur Startseite".
|
||||
- **U-6b** Route expected `SaveTransactionAsync` / `DeleteAccountAsync` / etc. exceptions to `IMessageService` — try/catch in each of the ~15 event handlers with a shared error-formatting helper.
|
||||
|
||||
### Phase 4 — Feedback + polish for mutations
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue