Clean up Story Intelligence review module chrome

This commit is contained in:
Nick Beckley 2026-08-29 10:27:47 +00:00
parent dd4b0badb6
commit 78f401b417
14 changed files with 87 additions and 385 deletions

View File

@ -236,8 +236,10 @@ var tests = new (string Name, Action Test)[]
("Story Intelligence Review Centre uses independent tile grid", StoryIntelligenceReviewCentreUsesIndependentTileGrid),
("Story Intelligence Review Centre opens with character gate", StoryIntelligenceReviewCentreOpensWithCharacterGate),
("Story Intelligence review modules are independent after character gate", StoryIntelligenceReviewModulesAreIndependentAfterCharacterGate),
("Story Intelligence review module pages omit wizard chrome", StoryIntelligenceReviewModulePagesOmitWizardChrome),
("Story Intelligence downstream review uses completed scene analysis", StoryIntelligenceDownstreamReviewUsesCompletedSceneAnalysis),
("Story Intelligence review posts do not use success interstitials", StoryIntelligenceReviewPostsDoNotUseSuccessInterstitials),
("Story Intelligence legacy review completion routes redirect to centre", StoryIntelligenceLegacyReviewCompletionRoutesRedirectToCentre),
("Story Intelligence review forms share busy submit guard", StoryIntelligenceReviewFormsShareBusySubmitGuard),
("Story Intelligence heavy review modules offer bounded rendering", StoryIntelligenceHeavyReviewModulesOfferBoundedRendering),
("Story Intelligence Review Centre adds no AI calls", StoryIntelligenceReviewCentreAddsNoAiCalls),
@ -742,6 +744,49 @@ static void StoryIntelligenceReviewModulesAreIndependentAfterCharacterGate()
Assert(locationsAction.Contains("RedirectToReviewCentreWithCharacterGate", StringComparison.Ordinal), "Direct dependent module URLs should return to Review Centre when the character gate is closed.");
}
static void StoryIntelligenceReviewModulePagesOmitWizardChrome()
{
var root = PlotLineRoot();
var reviewViews = new[]
{
("StoryIntelligenceCharacters.cshtml", "Review Characters"),
("StoryIntelligenceLocations.cshtml", "Review Locations"),
("StoryIntelligenceAssets.cshtml", "Review Assets"),
("StoryIntelligenceRelationships.cshtml", "Review Relationships"),
("StoryIntelligenceKnowledge.cshtml", "Review Knowledge"),
("StoryIntelligenceNarrative.cshtml", "Review Plot Lines & Threads")
};
var forbidden = new[]
{
"_StoryIntelligencePipelineHeader",
"_StoryIntelligencePipelineSummary",
"story-pipeline",
"story-future-stage",
"story-review-heading__phase",
"Phase 3",
"Review Story Intelligence",
"Next Stage",
"Previous Stage",
"Continue to Locations",
"Continue to Assets",
"Continue to Relationships",
"Continue to Knowledge"
};
foreach (var (viewName, title) in reviewViews)
{
var view = File.ReadAllText(Path.Combine(root, "Views/Onboarding", viewName));
Assert(view.Contains("<p class=\"eyebrow\">Story Intelligence</p>", StringComparison.Ordinal), $"{viewName} should use a simple module header eyebrow.");
Assert(view.Contains("StoryIntelligenceReviewCentre", StringComparison.Ordinal), $"{viewName} should return to Review Centre.");
Assert(view.Contains($">{title}</h1>", StringComparison.Ordinal), $"{viewName} should keep its focused module title.");
Assert(!view.Contains("StoryIntelligenceComplete", StringComparison.Ordinal), $"{viewName} should not route to the old final wizard step.");
foreach (var marker in forbidden)
{
Assert(!view.Contains(marker, StringComparison.OrdinalIgnoreCase), $"{viewName} should not render obsolete wizard chrome: {marker}.");
}
}
}
static void StoryIntelligenceDownstreamReviewUsesCompletedSceneAnalysis()
{
var root = PlotLineRoot();
@ -784,6 +829,29 @@ static void StoryIntelligenceReviewPostsDoNotUseSuccessInterstitials()
Assert(!postBlock.Contains("StoryIntelligenceNarrativeComplete", StringComparison.Ordinal), "Narrative post should not target success interstitial.");
}
static void StoryIntelligenceLegacyReviewCompletionRoutesRedirectToCentre()
{
var root = PlotLineRoot();
var controller = File.ReadAllText(Path.Combine(root, "Controllers/OnboardingController.cs"));
var completionActions = new[]
{
("StoryIntelligenceCharacterComplete", "characters"),
("StoryIntelligenceLocationComplete", "locations"),
("StoryIntelligenceAssetComplete", "assets"),
("StoryIntelligenceRelationshipComplete", "relationships"),
("StoryIntelligenceKnowledgeComplete", "knowledge"),
("StoryIntelligenceNarrativeComplete", "narrative")
};
foreach (var (action, route) in completionActions)
{
var block = ExtractBetween(controller, $"public IActionResult {action}", "}");
Assert(controller.Contains($"[HttpGet(\"story-intelligence/{route}/complete\")]", StringComparison.Ordinal), $"{action} legacy route should still exist.");
Assert(block.Contains("RedirectToAction(nameof(StoryIntelligenceReviewCentre)", StringComparison.Ordinal), $"{action} should redirect to Review Centre.");
Assert(!block.Contains("View(", StringComparison.Ordinal), $"{action} should not render a success interstitial.");
}
}
static void StoryIntelligenceReviewFormsShareBusySubmitGuard()
{
var root = PlotLineRoot();
@ -5105,7 +5173,6 @@ static void StoryIntelligenceNarrativeStageFollowsKnowledge()
var pipeline = File.ReadAllText(Path.Combine(root, "Services/StoryIntelligencePipelineStateService.cs"));
var onboarding = File.ReadAllText(Path.Combine(root, "Services/OnboardingStoryIntelligenceService.cs"));
var controller = File.ReadAllText(Path.Combine(root, "Controllers/OnboardingController.cs"));
var knowledgeComplete = File.ReadAllText(Path.Combine(root, "Views/Onboarding/StoryIntelligenceKnowledgeComplete.cshtml"));
var pipelineConstraint = File.ReadAllText(Path.Combine(root, "Sql/156_Phase25A_NarrativeReviewPipelineConstraint.sql"));
var knowledgeImport = File.ReadAllText(Path.Combine(root, "Services/StoryIntelligenceKnowledgeImportService.cs"));
@ -5117,7 +5184,7 @@ static void StoryIntelligenceNarrativeStageFollowsKnowledge()
Assert(knowledgeImport.Contains("hasUndecidedCandidates", StringComparison.Ordinal), "Knowledge review should be able to advance when prior decisions already imported every candidate.");
Assert(onboarding.Contains("SceneAnalysisComplete(state)\n ? StoryIntelligenceResumeRoutes.ReviewCentre", StringComparison.Ordinal), "Resume logic should route completed analysis to Review Centre.");
Assert(controller.Contains("StoryIntelligenceNarrative", StringComparison.Ordinal), "Onboarding controller should expose the narrative review stage.");
Assert(knowledgeComplete.Contains("Review Plot Lines & Threads", StringComparison.Ordinal), "Knowledge completion should lead to narrative review.");
Assert(controller.Contains("ImportStoryIntelligenceKnowledge", StringComparison.Ordinal) && controller.Contains("RedirectToAction(nameof(StoryIntelligenceReviewCentre)", StringComparison.Ordinal), "Knowledge completion should return to Review Centre instead of auto-advancing.");
}
static void WordCompanionReplaysLiveCurrentSceneToWritingPanes()

View File

@ -408,10 +408,9 @@ public sealed class OnboardingController(IOnboardingService onboarding, IOnboard
}
[HttpGet("story-intelligence/characters/complete")]
public async Task<IActionResult> StoryIntelligenceCharacterComplete(Guid batchId)
public IActionResult StoryIntelligenceCharacterComplete(Guid batchId)
{
var model = await storyIntelligence.GetCharacterImportResultAsync(batchId);
return model is null ? NotFound() : View(model);
return RedirectToAction(nameof(StoryIntelligenceReviewCentre), new { batchId });
}
[HttpPost("story-intelligence/locations")]
@ -431,10 +430,9 @@ public sealed class OnboardingController(IOnboardingService onboarding, IOnboard
}
[HttpGet("story-intelligence/locations/complete")]
public async Task<IActionResult> StoryIntelligenceLocationComplete(Guid batchId)
public IActionResult StoryIntelligenceLocationComplete(Guid batchId)
{
var model = await storyIntelligence.GetLocationImportResultAsync(batchId);
return model is null ? NotFound() : View(model);
return RedirectToAction(nameof(StoryIntelligenceReviewCentre), new { batchId });
}
[HttpPost("story-intelligence/assets")]
@ -454,10 +452,9 @@ public sealed class OnboardingController(IOnboardingService onboarding, IOnboard
}
[HttpGet("story-intelligence/assets/complete")]
public async Task<IActionResult> StoryIntelligenceAssetComplete(Guid batchId)
public IActionResult StoryIntelligenceAssetComplete(Guid batchId)
{
var model = await storyIntelligence.GetAssetImportResultAsync(batchId);
return model is null ? NotFound() : View(model);
return RedirectToAction(nameof(StoryIntelligenceReviewCentre), new { batchId });
}
[HttpPost("story-intelligence/relationships")]
@ -477,10 +474,9 @@ public sealed class OnboardingController(IOnboardingService onboarding, IOnboard
}
[HttpGet("story-intelligence/relationships/complete")]
public async Task<IActionResult> StoryIntelligenceRelationshipComplete(Guid batchId)
public IActionResult StoryIntelligenceRelationshipComplete(Guid batchId)
{
var model = await storyIntelligence.GetRelationshipImportResultAsync(batchId);
return model is null ? NotFound() : View(model);
return RedirectToAction(nameof(StoryIntelligenceReviewCentre), new { batchId });
}
[HttpGet("story-intelligence/knowledge")]
@ -527,10 +523,9 @@ public sealed class OnboardingController(IOnboardingService onboarding, IOnboard
}
[HttpGet("story-intelligence/knowledge/complete")]
public async Task<IActionResult> StoryIntelligenceKnowledgeComplete(Guid batchId)
public IActionResult StoryIntelligenceKnowledgeComplete(Guid batchId)
{
var model = await storyIntelligence.GetKnowledgeImportResultAsync(batchId);
return model is null ? NotFound() : View(model);
return RedirectToAction(nameof(StoryIntelligenceReviewCentre), new { batchId });
}
[HttpGet("story-intelligence/narrative")]
@ -577,10 +572,9 @@ public sealed class OnboardingController(IOnboardingService onboarding, IOnboard
}
[HttpGet("story-intelligence/narrative/complete")]
public async Task<IActionResult> StoryIntelligenceNarrativeComplete(Guid batchId)
public IActionResult StoryIntelligenceNarrativeComplete(Guid batchId)
{
var model = await storyIntelligence.GetNarrativeImportResultAsync(batchId);
return model is null ? NotFound() : View(model);
return RedirectToAction(nameof(StoryIntelligenceReviewCentre), new { batchId });
}
[HttpGet("story-intelligence/complete")]

View File

@ -1,57 +0,0 @@
@model StoryIntelligenceAssetImportResultViewModel
@{
ViewData["Title"] = "Assets created";
}
<section class="onboarding-shell" aria-labelledby="story-asset-complete-title">
<div class="onboarding-panel onboarding-review-panel">
<partial name="_StoryIntelligencePipelineHeader" model="@(new StoryIntelligencePipelineHeaderViewModel { CurrentStage = "Review Relationships" })" />
<div class="onboarding-copy">
<p class="eyebrow">Build Story Database</p>
<div class="onboarding-success-heading">
<span aria-hidden="true">&check;</span>
<h1 id="story-asset-complete-title">Assets created</h1>
</div>
<p>PlotDirector updated your story database from the approved asset decisions. Next, review the relationships detected between imported characters.</p>
</div>
<div class="onboarding-scan-counts onboarding-review-counts">
<div>
<span>Assets created</span>
<strong>@Model.AssetsCreated.ToString("N0")</strong>
</div>
<div>
<span>Assets linked</span>
<strong>@Model.AssetsLinked.ToString("N0")</strong>
</div>
<div>
<span>Aliases added</span>
<strong>@Model.AssetAliasesAdded.ToString("N0")</strong>
</div>
<div>
<span>Assets ignored</span>
<strong>@Model.AssetsIgnored.ToString("N0")</strong>
</div>
<div>
<span>Scene World panels updated</span>
<strong>@Model.SceneAssetEventsCreated.ToString("N0")</strong>
</div>
<div>
<span>Ownership links</span>
<strong>@Model.OwnershipLinksCreated.ToString("N0")</strong>
</div>
</div>
<div class="story-future-stage-grid">
<article class="story-future-stage"><strong>Review Relationships</strong><span>Next</span></article>
<article class="story-future-stage"><strong>Review Knowledge</strong><span>Coming Soon</span></article>
<article class="story-future-stage"><strong>Review Continuity</strong><span>Coming Soon</span></article>
<article class="story-future-stage"><strong>Timeline Events</strong><span>Coming Soon</span></article>
</div>
<div class="onboarding-actions">
<a class="btn btn-outline-secondary" asp-action="StoryIntelligenceAssets" asp-route-batchId="@Model.BatchID">Back to assets</a>
<a class="btn btn-primary" asp-action="StoryIntelligenceRelationships" asp-route-batchId="@Model.BatchID">Review relationships</a>
</div>
</div>
</section>

View File

@ -11,10 +11,8 @@
<section class="onboarding-shell" aria-labelledby="story-asset-title">
<div class="onboarding-panel onboarding-review-panel story-review-page">
<partial name="_StoryIntelligencePipelineHeader" model="@(new StoryIntelligencePipelineHeaderViewModel { CurrentStage = "Review Assets" })" />
<div class="onboarding-copy story-review-heading">
<p class="eyebrow">Phase 3</p>
<p class="story-review-heading__phase">Review Story Intelligence</p>
<p class="eyebrow">Story Intelligence</p>
<h1 id="story-asset-title">Review Assets</h1>
<p>Review important object suggestions that need a create, link, alias, or ignore decision.</p>
</div>
@ -28,8 +26,6 @@
<div class="alert alert-success">@message</div>
}
<partial name="_StoryIntelligencePipelineSummary" model="Model.PipelineDashboard" />
<section class="story-review-chapter-list" aria-label="Asset review">
@if (Model.AssetReview.Candidates.Count == 0)
{
@ -37,12 +33,6 @@
<strong>No asset decisions are waiting.</strong>
<p class="mb-0">Assets are already up to date, or there were no story-significant asset suggestions ready to import.</p>
</div>
<div class="story-future-stage-grid">
@FutureStage("Relationships")
@FutureStage("Knowledge")
@FutureStage("Plot Lines & Threads")
@FutureStage("Scene Metrics")
</div>
<div class="onboarding-actions">
<a class="btn btn-outline-secondary" asp-action="StoryIntelligenceReviewCentre" asp-route-batchId="@Model.BatchID">Back to Review Centre</a>
<form asp-action="ImportStoryIntelligenceAssets" method="post" data-story-review-form>
@ -240,7 +230,4 @@
@functions {
private static string Display(string? value) => string.IsNullOrWhiteSpace(value) ? "Not detected" : value;
private static Microsoft.AspNetCore.Html.IHtmlContent FutureStage(string label)
=> new Microsoft.AspNetCore.Html.HtmlString($"<article class=\"story-future-stage\"><strong>{System.Net.WebUtility.HtmlEncode(label)}</strong><span>Available from Review Centre</span></article>");
}

View File

@ -1,57 +0,0 @@
@model StoryIntelligenceCharacterImportResultViewModel
@{
ViewData["Title"] = "Characters created";
}
<section class="onboarding-shell" aria-labelledby="story-character-complete-title">
<div class="onboarding-panel onboarding-review-panel">
<partial name="_StoryIntelligencePipelineHeader" model="@(new StoryIntelligencePipelineHeaderViewModel { CurrentStage = "Review Locations" })" />
<div class="onboarding-copy">
<p class="eyebrow">Build Story Database</p>
<div class="onboarding-success-heading">
<span aria-hidden="true">&check;</span>
<h1 id="story-character-complete-title">Characters created</h1>
</div>
<p>PlotDirector updated your story database from the approved character decisions. The next Story Intelligence stages are ready to slot in as they are implemented.</p>
</div>
<div class="onboarding-scan-counts onboarding-review-counts">
<div>
<span>Characters created</span>
<strong>@Model.CharactersCreated.ToString("N0")</strong>
</div>
<div>
<span>Characters linked</span>
<strong>@Model.CharactersLinked.ToString("N0")</strong>
</div>
<div>
<span>Aliases added</span>
<strong>@Model.CharactersAliased.ToString("N0")</strong>
</div>
<div>
<span>Characters ignored</span>
<strong>@Model.CharactersIgnored.ToString("N0")</strong>
</div>
<div>
<span>POV links resolved</span>
<strong>@Model.PovLinksResolved.ToString("N0")</strong>
</div>
<div>
<span>Scene People panels updated</span>
<strong>@Model.ScenePeoplePanelsUpdated.ToString("N0")</strong>
</div>
</div>
<div class="story-future-stage-grid">
<article class="story-future-stage"><strong>Review Locations</strong><span>Next</span></article>
<article class="story-future-stage"><strong>Review Assets</strong><span>Coming Soon</span></article>
<article class="story-future-stage"><strong>Review Relationships</strong><span>Coming Soon</span></article>
<article class="story-future-stage"><strong>Review Knowledge</strong><span>Coming Soon</span></article>
</div>
<div class="onboarding-actions">
<a class="btn btn-outline-secondary" asp-action="StoryIntelligenceCharacters" asp-route-batchId="@Model.BatchID">Back to characters</a>
<a class="btn btn-primary" asp-action="StoryIntelligenceLocations" asp-route-batchId="@Model.BatchID">Review locations</a>
</div>
</div>
</section>

View File

@ -5,10 +5,8 @@
<section class="onboarding-shell" aria-labelledby="story-character-title">
<div class="onboarding-panel onboarding-review-panel story-review-page">
<partial name="_StoryIntelligencePipelineHeader" model="@(new StoryIntelligencePipelineHeaderViewModel { CurrentStage = "Review Characters" })" />
<div class="onboarding-copy story-review-heading">
<p class="eyebrow">Phase 3</p>
<p class="story-review-heading__phase">Review Story Intelligence</p>
<p class="eyebrow">Story Intelligence</p>
<h1 id="story-character-title">Review Characters</h1>
<p>Resolve character identity questions before reviewing the rest of the story intelligence.</p>
</div>
@ -37,12 +35,6 @@
<strong>No character decisions are waiting.</strong>
<p class="mb-0">Characters are already up to date, or there were no character suggestions ready to import.</p>
</div>
<div class="story-future-stage-grid">
@FutureStage("Locations")
@FutureStage("Assets")
@FutureStage("Relationships")
@FutureStage("Knowledge")
</div>
<div class="onboarding-actions">
<a class="btn btn-outline-secondary" asp-action="StoryIntelligenceReviewCentre" asp-route-batchId="@Model.BatchID">Back to Review Centre</a>
</div>
@ -244,7 +236,4 @@
private static bool IsDefault(StoryIntelligenceCharacterReviewCandidateViewModel candidate, string action)
=> string.Equals(candidate.DefaultAction, action, StringComparison.OrdinalIgnoreCase);
private static Microsoft.AspNetCore.Html.IHtmlContent FutureStage(string label)
=> new Microsoft.AspNetCore.Html.HtmlString($"<article class=\"story-future-stage\"><strong>{System.Net.WebUtility.HtmlEncode(label)}</strong><span>Available from Review Centre</span></article>");
}

View File

@ -11,10 +11,8 @@
<section class="onboarding-shell" aria-labelledby="story-knowledge-title">
<div class="onboarding-panel onboarding-review-panel story-review-page">
<partial name="_StoryIntelligencePipelineHeader" model="@(new StoryIntelligencePipelineHeaderViewModel { CurrentStage = "Review Knowledge" })" />
<div class="onboarding-copy story-review-heading">
<p class="eyebrow">Phase 3</p>
<p class="story-review-heading__phase">Review Story Intelligence</p>
<p class="eyebrow">Story Intelligence</p>
<h1 id="story-knowledge-title">Review Knowledge</h1>
<p>Review facts, discoveries, beliefs, and suspicions that need an author decision.</p>
</div>
@ -28,8 +26,6 @@
<div class="alert alert-success">@message</div>
}
<partial name="_StoryIntelligencePipelineSummary" model="Model.PipelineDashboard" />
<section class="story-review-chapter-list" aria-label="Knowledge review">
@if (Model.KnowledgeReview.Candidates.Count == 0)
{
@ -37,10 +33,6 @@
<strong>No knowledge decisions are waiting.</strong>
<p class="mb-0">Knowledge is already up to date, or there were no knowledge changes ready to import from the stored scene analysis.</p>
</div>
<div class="story-future-stage-grid">
@FutureStage("Plot Lines & Threads")
@FutureStage("Scene Metrics")
</div>
<div class="onboarding-actions">
<a class="btn btn-outline-secondary" asp-action="StoryIntelligenceReviewCentre" asp-route-batchId="@Model.BatchID">Back to Review Centre</a>
<form asp-action="ImportStoryIntelligenceKnowledge" method="post" data-story-review-form>
@ -244,7 +236,4 @@
@functions {
private static string Display(string? value) => string.IsNullOrWhiteSpace(value) ? "Not detected" : value;
private static Microsoft.AspNetCore.Html.IHtmlContent FutureStage(string label)
=> new Microsoft.AspNetCore.Html.HtmlString($"<article class=\"story-future-stage\"><strong>{System.Net.WebUtility.HtmlEncode(label)}</strong><span>Available from Review Centre</span></article>");
}

View File

@ -1,47 +0,0 @@
@model StoryIntelligenceKnowledgeImportResultViewModel
@{
ViewData["Title"] = "Knowledge created";
}
<section class="onboarding-shell" aria-labelledby="story-knowledge-complete-title">
<div class="onboarding-panel onboarding-review-panel">
<partial name="_StoryIntelligencePipelineHeader" model="@(new StoryIntelligencePipelineHeaderViewModel { CurrentStage = "Complete" })" />
<div class="onboarding-copy">
<p class="eyebrow">Build Story Database</p>
<div class="onboarding-success-heading">
<span aria-hidden="true">&check;</span>
<h1 id="story-knowledge-complete-title">Knowledge created</h1>
</div>
<p>PlotDirector updated the existing Knowledge Explorer from the approved Story Intelligence decisions.</p>
</div>
<div class="onboarding-scan-counts onboarding-review-counts">
<div>
<span>Knowledge created</span>
<strong>@Model.KnowledgeCreated.ToString("N0")</strong>
</div>
<div>
<span>Knowledge linked</span>
<strong>@Model.KnowledgeLinked.ToString("N0")</strong>
</div>
<div>
<span>Knowledge merged</span>
<strong>@Model.KnowledgeMerged.ToString("N0")</strong>
</div>
<div>
<span>Knowledge ignored</span>
<strong>@Model.KnowledgeIgnored.ToString("N0")</strong>
</div>
</div>
<div class="story-future-stage-grid">
<article class="story-future-stage"><strong>Review Continuity</strong><span>Coming Soon</span></article>
<article class="story-future-stage"><strong>Timeline Events</strong><span>Coming Soon</span></article>
</div>
<div class="onboarding-actions">
<a class="btn btn-outline-secondary" asp-action="StoryIntelligenceKnowledge" asp-route-batchId="@Model.BatchID">Back to knowledge</a>
<a class="btn btn-primary" asp-action="StoryIntelligenceNarrative" asp-route-batchId="@Model.BatchID">Review Plot Lines & Threads</a>
</div>
</div>
</section>

View File

@ -1,53 +0,0 @@
@model StoryIntelligenceLocationImportResultViewModel
@{
ViewData["Title"] = "Locations created";
}
<section class="onboarding-shell" aria-labelledby="story-location-complete-title">
<div class="onboarding-panel onboarding-review-panel">
<partial name="_StoryIntelligencePipelineHeader" model="@(new StoryIntelligencePipelineHeaderViewModel { CurrentStage = "Review Assets" })" />
<div class="onboarding-copy">
<p class="eyebrow">Build Story Database</p>
<div class="onboarding-success-heading">
<span aria-hidden="true">&check;</span>
<h1 id="story-location-complete-title">Locations created</h1>
</div>
<p>PlotDirector updated your story database from the approved location decisions. Future Story Intelligence stages will continue from here.</p>
</div>
<div class="onboarding-scan-counts onboarding-review-counts">
<div>
<span>Locations created</span>
<strong>@Model.LocationsCreated.ToString("N0")</strong>
</div>
<div>
<span>Locations linked</span>
<strong>@Model.LocationsLinked.ToString("N0")</strong>
</div>
<div>
<span>Aliases added</span>
<strong>@Model.LocationAliasesAdded.ToString("N0")</strong>
</div>
<div>
<span>Locations ignored</span>
<strong>@Model.LocationsIgnored.ToString("N0")</strong>
</div>
<div>
<span>Scene World panels updated</span>
<strong>@Model.SceneLocationsUpdated.ToString("N0")</strong>
</div>
</div>
<div class="story-future-stage-grid">
<article class="story-future-stage"><strong>Review Assets</strong><span>Next</span></article>
<article class="story-future-stage"><strong>Review Relationships</strong><span>Coming Soon</span></article>
<article class="story-future-stage"><strong>Review Knowledge</strong><span>Coming Soon</span></article>
<article class="story-future-stage"><strong>Review Continuity</strong><span>Coming Soon</span></article>
</div>
<div class="onboarding-actions">
<a class="btn btn-outline-secondary" asp-action="StoryIntelligenceLocations" asp-route-batchId="@Model.BatchID">Back to locations</a>
<a class="btn btn-primary" asp-action="StoryIntelligenceAssets" asp-route-batchId="@Model.BatchID">Review assets</a>
</div>
</div>
</section>

View File

@ -11,10 +11,8 @@
<section class="onboarding-shell" aria-labelledby="story-location-title">
<div class="onboarding-panel onboarding-review-panel story-review-page">
<partial name="_StoryIntelligencePipelineHeader" model="@(new StoryIntelligencePipelineHeaderViewModel { CurrentStage = "Review Locations" })" />
<div class="onboarding-copy story-review-heading">
<p class="eyebrow">Phase 3</p>
<p class="story-review-heading__phase">Review Story Intelligence</p>
<p class="eyebrow">Story Intelligence</p>
<h1 id="story-location-title">Review Locations</h1>
<p>Review place suggestions that need a create, link, alias, or ignore decision.</p>
</div>
@ -28,8 +26,6 @@
<div class="alert alert-success">@message</div>
}
<partial name="_StoryIntelligencePipelineSummary" model="Model.PipelineDashboard" />
<section class="story-review-chapter-list" aria-label="Location review">
@if (Model.LocationReview.Candidates.Count == 0)
{
@ -37,12 +33,6 @@
<strong>No location decisions are waiting.</strong>
<p class="mb-0">Locations are already up to date, or there were no location suggestions ready to import.</p>
</div>
<div class="story-future-stage-grid">
@FutureStage("Assets")
@FutureStage("Relationships")
@FutureStage("Knowledge")
@FutureStage("Plot Lines & Threads")
</div>
<div class="onboarding-actions">
<a class="btn btn-outline-secondary" asp-action="StoryIntelligenceReviewCentre" asp-route-batchId="@Model.BatchID">Back to Review Centre</a>
</div>
@ -228,7 +218,4 @@
@functions {
private static string Display(string? value) => string.IsNullOrWhiteSpace(value) ? "Not detected" : value;
private static Microsoft.AspNetCore.Html.IHtmlContent FutureStage(string label)
=> new Microsoft.AspNetCore.Html.HtmlString($"<article class=\"story-future-stage\"><strong>{System.Net.WebUtility.HtmlEncode(label)}</strong><span>Available from Review Centre</span></article>");
}

View File

@ -11,10 +11,8 @@
<section class="onboarding-shell" aria-labelledby="story-narrative-title">
<div class="onboarding-panel onboarding-review-panel story-review-page">
<partial name="_StoryIntelligencePipelineHeader" model="@(new StoryIntelligencePipelineHeaderViewModel { CurrentStage = "Review Plot Lines & Threads" })" />
<div class="onboarding-copy story-review-heading">
<p class="eyebrow">Phase 3</p>
<p class="story-review-heading__phase">Review Story Intelligence</p>
<p class="eyebrow">Story Intelligence</p>
<h1 id="story-narrative-title">Review Plot Lines & Threads</h1>
<p>Review recurring narrative arcs and thread candidates from the discovered hierarchy.</p>
</div>
@ -28,8 +26,6 @@
<div class="alert alert-success">@message</div>
}
<partial name="_StoryIntelligencePipelineSummary" model="Model.PipelineDashboard" />
@if (Model.NarrativeReview.Candidates.Count == 0)
{
<div class="story-review-note">

View File

@ -1,30 +0,0 @@
@model StoryIntelligenceNarrativeImportResultViewModel
@{
ViewData["Title"] = "Narrative review complete";
}
<section class="onboarding-shell" aria-labelledby="story-narrative-complete-title">
<div class="onboarding-panel onboarding-review-panel">
<partial name="_StoryIntelligencePipelineHeader" model="@(new StoryIntelligencePipelineHeaderViewModel { CurrentStage = "Complete" })" />
<div class="onboarding-copy">
<p class="eyebrow">Build Story Database</p>
<div class="onboarding-success-heading">
<span aria-hidden="true">&check;</span>
<h1 id="story-narrative-complete-title">Plot Lines & Threads reviewed</h1>
</div>
<p>PlotDirector applied the approved narrative candidates and left rejected candidates out of the canonical story database.</p>
</div>
<div class="onboarding-scan-counts onboarding-review-counts">
<div><span>Plot Lines created</span><strong>@Model.PlotLinesCreated.ToString("N0")</strong></div>
<div><span>Plot Lines merged</span><strong>@Model.PlotLinesMerged.ToString("N0")</strong></div>
<div><span>Threads created</span><strong>@Model.ThreadsCreated.ToString("N0")</strong></div>
<div><span>Rejected</span><strong>@Model.CandidatesRejected.ToString("N0")</strong></div>
</div>
<div class="onboarding-actions">
<a class="btn btn-outline-secondary" asp-action="StoryIntelligenceNarrative" asp-route-batchId="@Model.BatchID">Back to review</a>
<a class="btn btn-primary" asp-action="StoryIntelligenceComplete" asp-route-batchId="@Model.BatchID">Continue</a>
</div>
</div>
</section>

View File

@ -1,51 +0,0 @@
@model StoryIntelligenceRelationshipImportResultViewModel
@{
ViewData["Title"] = "Relationships created";
}
<section class="onboarding-shell" aria-labelledby="story-relationship-complete-title">
<div class="onboarding-panel onboarding-review-panel">
<partial name="_StoryIntelligencePipelineHeader" model="@(new StoryIntelligencePipelineHeaderViewModel { CurrentStage = "Complete" })" />
<div class="onboarding-copy">
<p class="eyebrow">Build Story Database</p>
<div class="onboarding-success-heading">
<span aria-hidden="true">&check;</span>
<h1 id="story-relationship-complete-title">Relationships created</h1>
</div>
<p>PlotDirector updated your story database from the approved relationship decisions. Next, review the knowledge changes detected in the imported scenes.</p>
</div>
<div class="onboarding-scan-counts onboarding-review-counts">
<div>
<span>Relationships created</span>
<strong>@Model.RelationshipsCreated.ToString("N0")</strong>
</div>
<div>
<span>Relationships linked</span>
<strong>@Model.RelationshipsLinked.ToString("N0")</strong>
</div>
<div>
<span>Relationships merged</span>
<strong>@Model.RelationshipsMerged.ToString("N0")</strong>
</div>
<div>
<span>Relationships ignored</span>
<strong>@Model.RelationshipsIgnored.ToString("N0")</strong>
</div>
<div>
<span>Relationship events added</span>
<strong>@Model.RelationshipEventsCreated.ToString("N0")</strong>
</div>
</div>
<div class="story-future-stage-grid">
<article class="story-future-stage"><strong>Review Continuity</strong><span>Coming Soon</span></article>
<article class="story-future-stage"><strong>Timeline Events</strong><span>Coming Soon</span></article>
</div>
<div class="onboarding-actions">
<a class="btn btn-outline-secondary" asp-action="StoryIntelligenceRelationships" asp-route-batchId="@Model.BatchID">Back to relationships</a>
<a class="btn btn-primary" asp-action="StoryIntelligenceKnowledge" asp-route-batchId="@Model.BatchID">Review knowledge</a>
</div>
</div>
</section>

View File

@ -11,10 +11,8 @@
<section class="onboarding-shell" aria-labelledby="story-relationship-title">
<div class="onboarding-panel onboarding-review-panel story-review-page">
<partial name="_StoryIntelligencePipelineHeader" model="@(new StoryIntelligencePipelineHeaderViewModel { CurrentStage = "Review Relationships" })" />
<div class="onboarding-copy story-review-heading">
<p class="eyebrow">Phase 3</p>
<p class="story-review-heading__phase">Review Story Intelligence</p>
<p class="eyebrow">Story Intelligence</p>
<h1 id="story-relationship-title">Review Relationships</h1>
<p>Review relationship suggestions by character pair and decide what should become canonical.</p>
</div>
@ -28,8 +26,6 @@
<div class="alert alert-success">@message</div>
}
<partial name="_StoryIntelligencePipelineSummary" model="Model.PipelineDashboard" />
<section class="story-review-chapter-list" aria-label="Relationship review">
@if (Model.RelationshipReview.Candidates.Count == 0)
{
@ -37,11 +33,6 @@
<strong>No relationship decisions are waiting.</strong>
<p class="mb-0">Relationships are already up to date, or there were no relationship suggestions ready to import from the stored scene analysis.</p>
</div>
<div class="story-future-stage-grid">
@FutureStage("Knowledge")
@FutureStage("Plot Lines & Threads")
@FutureStage("Scene Metrics")
</div>
<div class="onboarding-actions">
<a class="btn btn-outline-secondary" asp-action="StoryIntelligenceReviewCentre" asp-route-batchId="@Model.BatchID">Back to Review Centre</a>
<form asp-action="ImportStoryIntelligenceRelationships" method="post" data-story-review-form>
@ -255,7 +246,4 @@
@functions {
private static string Display(string? value) => string.IsNullOrWhiteSpace(value) ? "Not detected" : value;
private static Microsoft.AspNetCore.Html.IHtmlContent FutureStage(string label)
=> new Microsoft.AspNetCore.Html.HtmlString($"<article class=\"story-future-stage\"><strong>{System.Net.WebUtility.HtmlEncode(label)}</strong><span>Available from Review Centre</span></article>");
}