@model StoryIntelligenceProgressViewModel @{ ViewData["Title"] = "Story Intelligence Review Centre"; }

Story Intelligence

Review Centre

@(Model.CharacterGateSatisfied ? "Your manuscript analysis is complete. Choose any category to inspect or review." : "Resolve Characters first. Once character identities are confirmed, the remaining Story Intelligence categories can be reviewed in any order.")

@if (TempData["OnboardingStoryIntelligenceError"] is string error) {
@error
} @if (TempData["OnboardingStoryIntelligenceMessage"] is string message) {
@message
}
@ReviewModule( "Characters", Model.CharacterNeedsAttentionCount, Model.CharacterGateSatisfied, false, "Resolve character identities before reviewing dependent Story Intelligence.", Model.CharacterGateSatisfied ? "Review Characters" : "Resolve Characters", "StoryIntelligenceCharacters", true) @ReviewModule( "Assets", Model.AssetNeedsAttentionCount, Model.PipelineDashboard.AssetStageComplete, !Model.CharacterGateSatisfied, "Important objects and possessions found in the manuscript.", ModuleAction("Assets", Model.AssetNeedsAttentionCount, Model.PipelineDashboard.AssetStageComplete), "StoryIntelligenceAssets") @ReviewModule( "Knowledge", Model.KnowledgeNeedsAttentionCount, Model.PipelineDashboard.KnowledgeStageComplete, !Model.CharacterGateSatisfied, "Facts, discoveries, beliefs, and suspicions found in the manuscript.", ModuleAction("Knowledge", Model.KnowledgeNeedsAttentionCount, Model.PipelineDashboard.KnowledgeStageComplete), "StoryIntelligenceKnowledge") @ReviewModule( "Locations", Model.LocationNeedsAttentionCount, Model.PipelineDashboard.LocationStageComplete, !Model.CharacterGateSatisfied, "Places found in the manuscript.", ModuleAction("Locations", Model.LocationNeedsAttentionCount, Model.PipelineDashboard.LocationStageComplete), "StoryIntelligenceLocations") @ReviewPlotSynthesis() @ReviewModule( "Relationships", Model.RelationshipNeedsAttentionCount, Model.PipelineDashboard.RelationshipStageComplete, !Model.CharacterGateSatisfied, "Character relationships found in scene evidence.", ModuleAction("Relationships", Model.RelationshipNeedsAttentionCount, Model.PipelineDashboard.RelationshipStageComplete), "StoryIntelligenceRelationships") @ReviewMetrics(!Model.CharacterGateSatisfied) @if (Model.AnalysisIssueCount > 0) { @ReviewModule( "Analysis Issues", Model.AnalysisIssueCount, false, false, "Some chapters or scenes reported analysis issues.", "Return to Book", null) }
Return to Book Open Writer Workspace
@functions { private string ModuleAction(string title, int count, bool complete) => count > 0 && !complete ? $"Review {title}" : $"View {title}"; private Microsoft.AspNetCore.Html.IHtmlContent ReviewPlotSynthesis() { var blocked = !Model.CharacterGateSatisfied; var status = "Preparing analysis"; var statusClass = "story-review-centre-tile__status story-review-centre-tile__status--locked"; var description = "Whole-book plot synthesis starts after Characters are resolved."; var actionHtml = "Locked"; if (!blocked) { statusClass = "story-review-centre-tile__status story-review-centre-tile__status--ready"; if (Model.PlotSynthesis.IsQueued) { status = "Preparing"; description = "PlotDirector is preparing the whole-book plot synthesis."; actionHtml = "Preparing"; } else if (Model.PlotSynthesis.IsRunning) { status = "Analysing"; description = "PlotDirector is reading the full book to find sustained Plot Lines, Threads, and scene events."; actionHtml = "Analysing"; } else if (Model.PlotSynthesis.IsFailed) { status = "Failed"; statusClass = "story-review-centre-tile__status story-review-centre-tile__status--warning"; description = string.IsNullOrWhiteSpace(Model.PlotSynthesis.ErrorMessage) ? "Whole-book plot synthesis failed and can be retried." : Model.PlotSynthesis.ErrorMessage; actionHtml = $$"""
"""; } else if (Model.PlotSynthesis.IsCompleted && Model.NarrativeNeedsAttentionCount > 0) { status = $"{Model.NarrativeNeedsAttentionCount:N0} need attention"; statusClass = "story-review-centre-tile__status story-review-centre-tile__status--warning"; description = $"{Model.PlotSynthesis.ThreadCount:N0} thread candidates and {Model.PlotSynthesis.EventCount:N0} proposed scene events are ready."; var href = Url.Action("StoryIntelligenceNarrative", "Onboarding", new { batchId = Model.BatchID }) ?? "#"; actionHtml = $"Review Plot Lines & Threads"; } else if (Model.PipelineDashboard.NarrativeStageComplete) { status = "Complete"; description = "Plot Lines and Threads review has been saved."; var href = Url.Action("StoryIntelligenceNarrative", "Onboarding", new { batchId = Model.BatchID }) ?? "#"; actionHtml = $"View Plot Lines & Threads"; } else { description = "Plot synthesis will start automatically once character resolution is saved."; actionHtml = "Preparing"; } } return new Microsoft.AspNetCore.Html.HtmlString($$"""

Plot Lines & Threads

{{System.Net.WebUtility.HtmlEncode(description)}}

{{System.Net.WebUtility.HtmlEncode(status)}} {{actionHtml}}
"""); } private string StatusText(string title, int count, bool complete, bool blocked) { if (blocked) { return "Locked until Characters are resolved"; } if (string.Equals(title, "Scene Metrics", StringComparison.Ordinal)) { return "Available"; } if (complete) { return "Complete"; } return count switch { 0 => "No review needed", 1 => "1 needs attention", _ => $"{count:N0} need attention" }; } private Microsoft.AspNetCore.Html.IHtmlContent ReviewMetrics(bool blocked) { var status = StatusText("Scene Metrics", Model.TotalAnalysedScenes, false, blocked); var statusClass = blocked ? "story-review-centre-tile__status story-review-centre-tile__status--locked" : "story-review-centre-tile__status story-review-centre-tile__status--ready"; var actionHtml = blocked ? "Locked" : "View Metrics"; return new Microsoft.AspNetCore.Html.HtmlString($$"""

Scene Metrics

Auto-applied metrics from analysed scenes.

{{System.Net.WebUtility.HtmlEncode(status)}} {{actionHtml}}
"""); } private Microsoft.AspNetCore.Html.IHtmlContent ReviewModule( string title, int count, bool complete, bool blocked, string description, string actionLabel, string? action, bool primary = false) { var status = StatusText(title, count, complete, blocked); var statusClass = blocked ? "story-review-centre-tile__status story-review-centre-tile__status--locked" : count > 0 && !complete ? "story-review-centre-tile__status story-review-centre-tile__status--warning" : "story-review-centre-tile__status story-review-centre-tile__status--ready"; var tileClass = "story-review-centre-tile" + (primary ? " story-review-centre-tile--primary" : string.Empty) + (blocked ? " story-review-centre-tile--locked" : string.Empty); var href = action is null ? Url.Action("Details", "Books", new { id = Model.BookID }) ?? "#" : Url.Action(action, "Onboarding", new { batchId = Model.BatchID }) ?? "#"; var actionHtml = blocked ? "Locked" : $"{System.Net.WebUtility.HtmlEncode(actionLabel)}"; return new Microsoft.AspNetCore.Html.HtmlString($$"""

{{System.Net.WebUtility.HtmlEncode(title)}}

{{System.Net.WebUtility.HtmlEncode(description)}}

{{System.Net.WebUtility.HtmlEncode(status)}} {{actionHtml}}
"""); } }