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
<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>
@if (State.HasHealthIssue)
@@ -182,9 +191,12 @@
}
</div>
}
}
</div>
<CharacterFormModal
@if (IsInitialized)
{
<CharacterFormModal
Visible="State.ShowCreateCharacterModal"
Title="Create Character"
SubmitLabel="Create Character"
@@ -201,7 +213,7 @@
CharacterSaved="Campaigns.OnCharacterCreatedAsync"
CancelRequested="Campaigns.CloseCharacterModals"/>
<CharacterFormModal
<CharacterFormModal
Visible="State.ShowEditCharacterModal"
Title="Edit Character"
SubmitLabel="Save Character"
@@ -218,7 +230,7 @@
CharacterSaved="Campaigns.OnCharacterUpdatedAsync"
CancelRequested="Campaigns.CloseCharacterModals"/>
<RolemasterSkillRollModal
<RolemasterSkillRollModal
Visible="State.ShowRolemasterSkillRollModal"
SkillName="@(State.PendingRolemasterSkillRoll?.Name ?? string.Empty)"
Expression="@(State.PendingRolemasterSkillRoll?.DiceRollDefinition ?? string.Empty)"
@@ -229,3 +241,4 @@
IsSubmitting="State.IsSubmittingRolemasterSkillRoll"
ConfirmRequested="Play.SubmitRolemasterSkillRollAsync"
CancelRequested="Play.CancelRolemasterSkillRollAsync"/>
}

View File

@@ -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<string?> LoggedOut { get; set; }
[Parameter] public EventCallback<string?> 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<AppHeaderMenuItem> HeaderMenuItems
{