Delay workspace render until session init completes

This commit is contained in:
2026-05-04 18:12:10 +02:00
parent 231b0ac9a0
commit da813583bd
2 changed files with 249 additions and 226 deletions

View File

@@ -1,5 +1,14 @@
@using RpgRoller.Components.Pages.HomeControls @using RpgRoller.Components.Pages.HomeControls
<div class="@State.AppCssClass"> <div class="@State.AppCssClass">
@if (!IsInitialized)
{
<main class="loading-shell" aria-busy="true" aria-live="polite">
<h1>RpgRoller</h1>
<p>Loading workspace...</p>
</main>
}
else
{
<p class="sr-only" aria-live="polite">@State.LiveAnnouncement</p> <p class="sr-only" aria-live="polite">@State.LiveAnnouncement</p>
@if (State.HasHealthIssue) @if (State.HasHealthIssue)
@@ -182,9 +191,12 @@
} }
</div> </div>
} }
}
</div> </div>
<CharacterFormModal @if (IsInitialized)
{
<CharacterFormModal
Visible="State.ShowCreateCharacterModal" Visible="State.ShowCreateCharacterModal"
Title="Create Character" Title="Create Character"
SubmitLabel="Create Character" SubmitLabel="Create Character"
@@ -201,7 +213,7 @@
CharacterSaved="Campaigns.OnCharacterCreatedAsync" CharacterSaved="Campaigns.OnCharacterCreatedAsync"
CancelRequested="Campaigns.CloseCharacterModals"/> CancelRequested="Campaigns.CloseCharacterModals"/>
<CharacterFormModal <CharacterFormModal
Visible="State.ShowEditCharacterModal" Visible="State.ShowEditCharacterModal"
Title="Edit Character" Title="Edit Character"
SubmitLabel="Save Character" SubmitLabel="Save Character"
@@ -218,7 +230,7 @@
CharacterSaved="Campaigns.OnCharacterUpdatedAsync" CharacterSaved="Campaigns.OnCharacterUpdatedAsync"
CancelRequested="Campaigns.CloseCharacterModals"/> CancelRequested="Campaigns.CloseCharacterModals"/>
<RolemasterSkillRollModal <RolemasterSkillRollModal
Visible="State.ShowRolemasterSkillRollModal" Visible="State.ShowRolemasterSkillRollModal"
SkillName="@(State.PendingRolemasterSkillRoll?.Name ?? string.Empty)" SkillName="@(State.PendingRolemasterSkillRoll?.Name ?? string.Empty)"
Expression="@(State.PendingRolemasterSkillRoll?.DiceRollDefinition ?? string.Empty)" Expression="@(State.PendingRolemasterSkillRoll?.DiceRollDefinition ?? string.Empty)"
@@ -229,3 +241,4 @@
IsSubmitting="State.IsSubmittingRolemasterSkillRoll" IsSubmitting="State.IsSubmittingRolemasterSkillRoll"
ConfirmRequested="Play.SubmitRolemasterSkillRollAsync" ConfirmRequested="Play.SubmitRolemasterSkillRollAsync"
CancelRequested="Play.CancelRolemasterSkillRollAsync"/> CancelRequested="Play.CancelRolemasterSkillRollAsync"/>
}

View File

@@ -16,6 +16,7 @@ public partial class Workspace : IAsyncDisposable
return; return;
await Session.InitializeAsync(); await Session.InitializeAsync();
IsInitialized = true;
await InvokeAsync(StateHasChanged); await InvokeAsync(StateHasChanged);
} }
@@ -87,36 +88,45 @@ public partial class Workspace : IAsyncDisposable
return exception.Message.Contains("statically rendered", StringComparison.OrdinalIgnoreCase); return exception.Message.Contains("statically rendered", StringComparison.OrdinalIgnoreCase);
} }
[Inject] [Inject] private IJSRuntime JS { get; set; } = null!;
private IJSRuntime JS { get; set; } = null!;
[Inject] [Inject] private RpgRollerApiClient ApiClient { get; set; } = null!;
private RpgRollerApiClient ApiClient { get; set; } = null!;
[Inject] [Inject] private WorkspaceQueryService WorkspaceQuery { get; set; } = null!;
private WorkspaceQueryService WorkspaceQuery { get; set; } = null!;
[Inject] [Inject] private NavigationManager Navigation { get; set; } = null!;
private NavigationManager Navigation { get; set; } = null!;
[Parameter] [Parameter] public EventCallback<string?> LoggedOut { get; set; }
public EventCallback<string?> LoggedOut { get; set; }
private bool IsInitialized { get; set; }
private WorkspaceState State { get; } = new(); 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 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<AppHeaderMenuItem> HeaderMenuItems private IReadOnlyList<AppHeaderMenuItem> HeaderMenuItems
{ {