@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.PipelineDashboard.CharacterStageComplete, false, "Resolve character identities before reviewing dependent Story Intelligence.", "Review Characters", "StoryIntelligenceCharacters", "View Characters", "Characters", new { projectId = Model.ProjectID }, true) @ReviewModule( "Assets", Model.AssetNeedsAttentionCount, Model.PipelineDashboard.AssetStageComplete, !Model.CharacterGateSatisfied, "Important objects and possessions found in the manuscript.", "Review Assets", "StoryIntelligenceAssets", "View Assets", "StoryAssets", new { projectId = Model.ProjectID }) @ReviewModule( "Knowledge", Model.KnowledgeNeedsAttentionCount, Model.PipelineDashboard.KnowledgeStageComplete, !Model.CharacterGateSatisfied, "Facts, discoveries, beliefs, and suspicions found in the manuscript.", "Review Knowledge", "StoryIntelligenceKnowledge", "View Knowledge", "StoryBible", new { projectId = Model.ProjectID }) @ReviewModule( "Locations", Model.LocationNeedsAttentionCount, Model.PipelineDashboard.LocationStageComplete, !Model.CharacterGateSatisfied, "Places found in the manuscript.", "Review Locations", "StoryIntelligenceLocations", "View Locations", "Locations", new { projectId = Model.ProjectID }) @ReviewPlotSynthesis() @ReviewModule( "Relationships", Model.RelationshipNeedsAttentionCount, Model.PipelineDashboard.RelationshipStageComplete, !Model.CharacterGateSatisfied, "Character relationships found in scene evidence.", "Review Relationships", "StoryIntelligenceRelationships", "View Relationships", "RelationshipMap", new { projectId = Model.ProjectID, bookId = Model.BookID }) @ReviewMetrics(!Model.CharacterGateSatisfied) @if (Model.AnalysisIssueCount > 0) { @ReviewModule( "Analysis Issues", Model.AnalysisIssueCount, false, false, "Some chapters or scenes reported analysis issues.", "Return to Book", "StoryIntelligenceReviewCentre", "Return to Book", "Books", new { id = Model.BookID }) }
Return to Book Open Writer Workspace
@functions { 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.GetValueOrDefault() > 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("Index", "Timeline", new { projectId = Model.ProjectID, bookId = Model.BookID }) ?? "#"; actionHtml = $"View on Timeline"; } 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 Model.MetricValueCount > 0 ? "Available" : "No metrics available"; } if (complete) { return "Complete"; } if (!count.HasValue) { return "Ready"; } return count switch { 0 => "No review needed", 1 => "1 needs attention", _ => $"{count:N0} need attention" }; } private Microsoft.AspNetCore.Html.IHtmlContent ReviewMetrics(bool blocked) { var hasMetrics = Model.MetricValueCount > 0; var status = StatusText("Scene Metrics", Model.MetricValueCount, false, blocked); var statusClass = blocked ? "story-review-centre-tile__status story-review-centre-tile__status--locked" : hasMetrics ? "story-review-centre-tile__status story-review-centre-tile__status--ready" : "story-review-centre-tile__status story-review-centre-tile__status--locked"; var href = Url.Action("Index", "Timeline", new { projectId = Model.ProjectID, bookId = Model.BookID }) ?? "#"; var actionHtml = blocked ? "Locked" : hasMetrics ? $"View on Timeline" : "No action"; 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 reviewActionLabel, string reviewAction, string completeActionLabel, string completeController, object completeRouteValues, 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.GetValueOrDefault() > 0 || (!complete && !count.HasValue)) ? "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 = complete ? Url.Action("Index", completeController, completeRouteValues) ?? "#" : Url.Action(reviewAction, "Onboarding", new { batchId = Model.BatchID }) ?? "#"; var actionLabel = complete ? completeActionLabel : reviewActionLabel; 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}}
"""); } }