From da813583bd5a2cbb8d42dd4a513d38067d907895 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 4 May 2026 18:12:10 +0200 Subject: [PATCH] Delay workspace render until session init completes --- RpgRoller/Components/Pages/Workspace.razor | 433 +++++++++--------- RpgRoller/Components/Pages/Workspace.razor.cs | 42 +- 2 files changed, 249 insertions(+), 226 deletions(-) diff --git a/RpgRoller/Components/Pages/Workspace.razor b/RpgRoller/Components/Pages/Workspace.razor index 3c3a06f..ca7d67e 100644 --- a/RpgRoller/Components/Pages/Workspace.razor +++ b/RpgRoller/Components/Pages/Workspace.razor @@ -1,231 +1,244 @@ @using RpgRoller.Components.Pages.HomeControls
-

@State.LiveAnnouncement

- - @if (State.HasHealthIssue) + @if (!IsInitialized) { - +
+

RpgRoller

+

Loading workspace...

+
} + else + { +

@State.LiveAnnouncement

-
- - - @if (State.IsPlayScreen) + @if (State.HasHealthIssue) { -
- +
+ API currently unavailable. +

@State.HealthIssueMessage

+
+ + + } + +
+ + + @if (State.IsPlayScreen) + { +
+ + + +
+ + } + else if (State.IsManagementScreen) + { + - - -
- - } - else if (State.IsManagementScreen) - { - - } - else if (State.IsAdminScreen) - { -
- @if (State.IsCurrentUserAdmin) - { + DeleteCharacterRequested="Campaigns.DeleteCharacterAsync"/> + } + else if (State.IsAdminScreen) + { +
+ @if (State.IsCurrentUserAdmin) + { +
+
+

Database

+
+

Download the current SQLite file for backup or offline inspection.

+ +
+ }
-

Database

-
-

Download the current SQLite file for backup or offline inspection.

-
- Download SQLite database +

User Management

+ @if (State.IsAdminDataLoading) + { +

Loading users...

+ } + else if (!State.IsCurrentUserAdmin) + { +

Admin role is required to manage users.

+ } + else if (State.AdminUsers.Count == 0) + { +

No users found.

+ } + else + { +
    + @foreach (var user in State.AdminUsers) + { +
  • +
    + @user.Username +

    @user.DisplayName

    +

    Roles: @(user.Roles.Count == 0 ? "none" : string.Join(", ", user.Roles))

    +
    +
    + + +
    +
  • + } +
+ }
- } -
-
-

User Management

-
- @if (State.IsAdminDataLoading) - { -

Loading users...

- } - else if (!State.IsCurrentUserAdmin) - { -

Admin role is required to manage users.

- } - else if (State.AdminUsers.Count == 0) - { -

No users found.

- } - else - { -
    - @foreach (var user in State.AdminUsers) - { -
  • -
    - @user.Username -

    @user.DisplayName

    -

    Roles: @(user.Roles.Count == 0 ? "none" : string.Join(", ", user.Roles))

    -
    -
    - - -
    -
  • - } -
- } -
-
- } -
- - @if (State.Toasts.Count > 0) - { -
- @foreach (var toast in State.Toasts) - { -
-

@toast.Message

-
+ }
+ + @if (State.Toasts.Count > 0) + { +
+ @foreach (var toast in State.Toasts) + { +
+

@toast.Message

+
+ } +
+ } }
- +@if (IsInitialized) +{ + - + - \ No newline at end of file + +} diff --git a/RpgRoller/Components/Pages/Workspace.razor.cs b/RpgRoller/Components/Pages/Workspace.razor.cs index f560652..11c62f9 100644 --- a/RpgRoller/Components/Pages/Workspace.razor.cs +++ b/RpgRoller/Components/Pages/Workspace.razor.cs @@ -16,6 +16,7 @@ public partial class Workspace : IAsyncDisposable return; await Session.InitializeAsync(); + IsInitialized = true; await InvokeAsync(StateHasChanged); } @@ -87,36 +88,45 @@ public partial class Workspace : IAsyncDisposable return exception.Message.Contains("statically rendered", StringComparison.OrdinalIgnoreCase); } - [Inject] - private IJSRuntime JS { get; set; } = null!; + [Inject] private IJSRuntime JS { get; set; } = null!; - [Inject] - private RpgRollerApiClient ApiClient { get; set; } = null!; + [Inject] private RpgRollerApiClient ApiClient { get; set; } = null!; - [Inject] - private WorkspaceQueryService WorkspaceQuery { get; set; } = null!; + [Inject] private WorkspaceQueryService WorkspaceQuery { get; set; } = null!; - [Inject] - private NavigationManager Navigation { get; set; } = null!; + [Inject] private NavigationManager Navigation { get; set; } = null!; - [Parameter] - public EventCallback LoggedOut { get; set; } + [Parameter] public EventCallback LoggedOut { get; set; } + private bool IsInitialized { get; set; } private WorkspaceState State { get; } = new(); - private WorkspaceCampaignScopeCoordinator Scope => m_Scope ??= new(State, Feedback, JS, WorkspaceQuery, Play.EnsureSelectedCharacterActiveAsync, Play.RefreshSelectedCharacterSheetAsync, Play.RefreshCampaignLogAsync, Play.ResetCampaignLogDetailState, Play.ResetCampaignStateTracking, ClearAuthenticatedState, StopStateEventsAsync, message => LoggedOut.InvokeAsync(message)); + private WorkspaceCampaignScopeCoordinator Scope => m_Scope ??= new(State, Feedback, JS, WorkspaceQuery, + Play.EnsureSelectedCharacterActiveAsync, Play.RefreshSelectedCharacterSheetAsync, Play.RefreshCampaignLogAsync, + Play.ResetCampaignLogDetailState, Play.ResetCampaignStateTracking, ClearAuthenticatedState, + StopStateEventsAsync, message => LoggedOut.InvokeAsync(message)); - private WorkspaceLiveStateController Live => m_Live ??= new(State, Feedback, StartStateEventsCoreAsync, StopStateEventsCoreAsync, Scope.RefreshCampaignRosterAsync, Play.RefreshSelectedCharacterSheetAsync, Play.RefreshCampaignLogAsync, () => InvokeAsync(StateHasChanged)); + private WorkspaceLiveStateController Live => m_Live ??= new(State, Feedback, StartStateEventsCoreAsync, + StopStateEventsCoreAsync, Scope.RefreshCampaignRosterAsync, Play.RefreshSelectedCharacterSheetAsync, + Play.RefreshCampaignLogAsync, () => InvokeAsync(StateHasChanged)); - private WorkspacePlayCoordinator Play => m_Play ??= new(State, Feedback, ApiClient, WorkspaceQuery, CanEditCharacter, () => InvokeAsync(StateHasChanged)); + private WorkspacePlayCoordinator Play => m_Play ??= new(State, Feedback, ApiClient, WorkspaceQuery, + CanEditCharacter, () => InvokeAsync(StateHasChanged)); - private WorkspaceCampaignCoordinator Campaigns => m_Campaigns ??= new(State, Feedback, JS, ApiClient, Session.LoadKnownUsernamesAsync, Scope.ReloadCampaignsAsync, Scope.ReloadCharacterCampaignOptionsAsync, Scope.RefreshCampaignScopeAsync, Live.SyncStateEventsAsync); + private WorkspaceCampaignCoordinator Campaigns => m_Campaigns ??= new(State, Feedback, JS, ApiClient, + Session.LoadKnownUsernamesAsync, Scope.ReloadCampaignsAsync, Scope.ReloadCharacterCampaignOptionsAsync, + Scope.RefreshCampaignScopeAsync, Live.SyncStateEventsAsync); - private WorkspaceAdminCoordinator Admin => m_Admin ??= new(State, Feedback, JS, ApiClient, WorkspaceQuery, ClearAuthenticatedState, StopStateEventsAsync, message => LoggedOut.InvokeAsync(message)); + private WorkspaceAdminCoordinator Admin => m_Admin ??= new(State, Feedback, JS, ApiClient, WorkspaceQuery, + ClearAuthenticatedState, StopStateEventsAsync, message => LoggedOut.InvokeAsync(message)); private WorkspaceFeedbackService Feedback => m_Feedback ??= new(State, () => InvokeAsync(StateHasChanged)); - private WorkspaceSessionCoordinator Session => m_Session ??= new(State, Feedback, JS, ApiClient, WorkspaceQuery, Scope.ReloadCampaignsAsync, Scope.ReloadCharacterCampaignOptionsAsync, Scope.RefreshCampaignScopeAsync, Live.SyncStateEventsAsync, Live.StopStateEventsAsync, EnsureAdminUsersLoadedAsync, Play.ResetCampaignLogDetailState, () => InvokeAsync(StateHasChanged), message => LoggedOut.InvokeAsync(message)); + private WorkspaceSessionCoordinator Session => m_Session ??= new(State, Feedback, JS, ApiClient, WorkspaceQuery, + Scope.ReloadCampaignsAsync, Scope.ReloadCharacterCampaignOptionsAsync, Scope.RefreshCampaignScopeAsync, + Live.SyncStateEventsAsync, Live.StopStateEventsAsync, EnsureAdminUsersLoadedAsync, + Play.ResetCampaignLogDetailState, () => InvokeAsync(StateHasChanged), + message => LoggedOut.InvokeAsync(message)); private IReadOnlyList HeaderMenuItems {