Fix basic location onboarding wizard UI
This commit is contained in:
parent
66e28b7f0e
commit
b6caf9df8e
@ -3930,8 +3930,8 @@ static void CoreImportWizardOrdersScenesBeforeCharacters()
|
||||
Assert(onboarding.Contains("ValidateScanReview(new ManuscriptScanReviewDecision", StringComparison.Ordinal), "Character validation should run when finalising character review.");
|
||||
Assert(onboarding.Contains("Import the approved chapters and scenes before reviewing characters.", StringComparison.Ordinal), "Character finalisation should refuse to run before structural scenes exist.");
|
||||
Assert(complete.Contains("Detected scene structure", StringComparison.Ordinal), "Scene detection result page should show detected counts by chapter.");
|
||||
Assert(complete.Contains("Review characters", StringComparison.Ordinal), "After Word sync, the next onboarding step should be character review.");
|
||||
Assert(complete.Contains("Keep this browser workflow open to review characters.", StringComparison.Ordinal), "Scene detection completion should continue to character review without marking optional Story Intelligence as required.");
|
||||
Assert(complete.Contains("Review locations", StringComparison.Ordinal), "After Word sync, the next onboarding step should be location review.");
|
||||
Assert(complete.Contains("Keep this browser workflow open to review locations.", StringComparison.Ordinal), "Scene detection completion should continue to location review without marking optional Story Intelligence as required.");
|
||||
}
|
||||
|
||||
static void CoreImportRemapsCharactersAfterReview()
|
||||
@ -4533,12 +4533,13 @@ static void OnboardingWizardKeepsCharacterPagesInsideOneMainStep()
|
||||
|
||||
Assert(!header.Contains("BuildDynamicSteps", StringComparison.Ordinal), "Onboarding header should not create one top-level step per character page.");
|
||||
Assert(header.Contains("new(\"Detect Scenes\", 8)", StringComparison.Ordinal), "Onboarding header should include scene detection as a distinct main step.");
|
||||
Assert(header.Contains("new(\"Review Characters\", 9)", StringComparison.Ordinal), "Onboarding header should keep character review as one main step.");
|
||||
Assert(header.Contains("new(\"Review Locations\", 9)", StringComparison.Ordinal), "Onboarding header should include basic location review as a distinct main step.");
|
||||
Assert(header.Contains("new(\"Review Characters\", 10)", StringComparison.Ordinal), "Onboarding header should keep character review as one main step.");
|
||||
Assert(!header.Contains("Story Summary", StringComparison.Ordinal), "Core onboarding header should not present Story Summary as a mandatory import step.");
|
||||
Assert(!header.Contains("Story Context", StringComparison.Ordinal), "Core onboarding header should not present Story Context as a mandatory import step.");
|
||||
Assert(review.Contains("var currentStep = isCharacterStep ? 9 : 7;", StringComparison.Ordinal), "Scan review should keep every character page on the same main wizard step.");
|
||||
Assert(review.Contains("var currentStep = isCharacterStep ? 10 : 7;", StringComparison.Ordinal), "Scan review should keep every character page on the same main wizard step.");
|
||||
Assert(review.Contains("onboarding-subprogress", StringComparison.Ordinal), "Character pagination should be shown as section-level progress.");
|
||||
Assert(storyService.Contains("const int totalWizardSteps = 10;", StringComparison.Ordinal), "Story Intelligence summary/context should use the fixed core wizard step count.");
|
||||
Assert(storyService.Contains("const int totalWizardSteps = 11;", StringComparison.Ordinal), "Story Intelligence summary/context should use the fixed core wizard step count.");
|
||||
}
|
||||
|
||||
static void StoryIntelligenceExperienceBootDoesNotSerialiseLiveModel()
|
||||
|
||||
@ -93,6 +93,7 @@ public sealed class OnboardingController(
|
||||
}
|
||||
|
||||
[HttpGet("scan-locations")]
|
||||
[HttpGet("scan/locations")]
|
||||
public async Task<IActionResult> ScanLocations(Guid previewId)
|
||||
{
|
||||
var model = await onboarding.GetBasicLocationReviewAsync(previewId);
|
||||
@ -112,6 +113,7 @@ public sealed class OnboardingController(
|
||||
}
|
||||
|
||||
[HttpPost("scan-locations")]
|
||||
[HttpPost("scan/locations")]
|
||||
[RequestFormLimits(ValueCountLimit = 20000, KeyLengthLimit = 4096, ValueLengthLimit = 1024 * 1024)]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> SaveBasicLocations(CoreImportBasicLocationReviewForm form, string intent = "save")
|
||||
|
||||
@ -88,7 +88,7 @@ public sealed class OnboardingStoryIntelligenceService(
|
||||
var missingTextCount = included.Count(chapter => string.IsNullOrWhiteSpace(chapter.Preview.ChapterText));
|
||||
const int storySummaryStep = 10;
|
||||
const int storyContextStep = 10;
|
||||
const int totalWizardSteps = 10;
|
||||
const int totalWizardSteps = 11;
|
||||
return new StoryIntelligenceOverviewViewModel
|
||||
{
|
||||
PreviewID = preview.PreviewID,
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
<section class="onboarding-shell" aria-labelledby="build-complete-title">
|
||||
<div class="onboarding-panel onboarding-review-panel">
|
||||
<partial name="_OnboardingJourneyHeader" model="@(new OnboardingJourneyHeaderViewModel { CurrentStep = coreComplete ? 10 : 8, TotalSteps = 10 })" />
|
||||
<partial name="_OnboardingJourneyHeader" model="@(new OnboardingJourneyHeaderViewModel { CurrentStep = coreComplete ? 11 : 8, TotalSteps = 11 })" />
|
||||
<div class="onboarding-copy">
|
||||
<p class="eyebrow">@(coreComplete ? "Core Import Complete" : "Scene Detection Complete")</p>
|
||||
<div class="onboarding-success-heading">
|
||||
@ -20,11 +20,11 @@
|
||||
}
|
||||
else if (Model.AlreadyBuilt)
|
||||
{
|
||||
@:This manuscript structure has already been created in PlotDirector, so nothing was duplicated. Review characters to complete the core import.
|
||||
@:This manuscript structure has already been created in PlotDirector, so nothing was duplicated. Review locations before reviewing characters to complete the core import.
|
||||
}
|
||||
else
|
||||
{
|
||||
@:@Model.ScenesCreated.ToString("N0") scenes imported across @Model.ChaptersCreated.ToString("N0") chapters. Keep this browser workflow open to review characters.
|
||||
@:@Model.ScenesCreated.ToString("N0") scenes imported across @Model.ChaptersCreated.ToString("N0") chapters. Keep this browser workflow open to review locations.
|
||||
}
|
||||
</p>
|
||||
@if (!string.IsNullOrWhiteSpace(Model.MarkerWarning))
|
||||
@ -87,8 +87,8 @@
|
||||
else
|
||||
{
|
||||
<section class="onboarding-complete-next">
|
||||
<h2>Next: review characters</h2>
|
||||
<p>Character detection remains part of core import. Review detected names, aliases and existing matches to finish importing the manuscript.</p>
|
||||
<h2>Next: review locations</h2>
|
||||
<p>Basic location review is part of core import. Review detected places before reviewing characters and finishing the manuscript import.</p>
|
||||
</section>
|
||||
|
||||
<section class="onboarding-build-panel onboarding-marker-resync-panel" data-onboarding-build-panel>
|
||||
|
||||
@ -4,22 +4,24 @@
|
||||
}
|
||||
|
||||
<section class="onboarding-shell">
|
||||
<div class="onboarding-header">
|
||||
<p class="eyebrow">Core import</p>
|
||||
<h1>Review locations</h1>
|
||||
<p class="lede">@Model.DocumentTitle - @Model.SelectedProjectName - @Model.SelectedBookTitle</p>
|
||||
</div>
|
||||
<div class="onboarding-panel onboarding-review-panel onboarding-location-review-panel">
|
||||
<partial name="_OnboardingJourneyHeader" model="@(new OnboardingJourneyHeaderViewModel { CurrentStep = 9, TotalSteps = 11 })" />
|
||||
|
||||
@if (TempData["OnboardingReviewMessage"] is string message)
|
||||
{
|
||||
<div class="alert alert-success">@message</div>
|
||||
}
|
||||
@if (TempData["ArchiveError"] is string error)
|
||||
{
|
||||
<div class="alert alert-danger">@error</div>
|
||||
}
|
||||
<div class="onboarding-copy">
|
||||
<p class="eyebrow">Core import</p>
|
||||
<h1 id="scan-location-review-title">Review Locations</h1>
|
||||
<p>@Model.DocumentTitle - @Model.SelectedProjectName - @Model.SelectedBookTitle</p>
|
||||
</div>
|
||||
|
||||
@if (TempData["OnboardingReviewMessage"] is string message)
|
||||
{
|
||||
<div class="alert alert-success">@message</div>
|
||||
}
|
||||
@if (TempData["ArchiveError"] is string error)
|
||||
{
|
||||
<div class="alert alert-danger">@error</div>
|
||||
}
|
||||
|
||||
<div class="onboarding-panel">
|
||||
<div class="review-summary-grid">
|
||||
<div>
|
||||
<span class="metric-label">Raw observations</span>
|
||||
@ -42,8 +44,11 @@
|
||||
<article class="location-review-row">
|
||||
<input type="hidden" name="Locations[@i].StableKey" value="@candidate.StableKey" />
|
||||
<div class="location-review-main">
|
||||
<h2>@candidate.ProposedName</h2>
|
||||
<p>@candidate.ObservationCount observation@(candidate.ObservationCount == 1 ? "" : "s") - first seen in Chapter @candidate.FirstChapterNumber, Scene @candidate.FirstSceneNumber</p>
|
||||
<div class="location-review-title-row">
|
||||
<h2>@candidate.ProposedName</h2>
|
||||
<span>@candidate.ObservationCount observation@(candidate.ObservationCount == 1 ? "" : "s")</span>
|
||||
</div>
|
||||
<p>First seen in Chapter @candidate.FirstChapterNumber, Scene @candidate.FirstSceneNumber</p>
|
||||
@if (candidate.KnownNames.Count > 1)
|
||||
{
|
||||
<p>Known names: @string.Join(", ", candidate.KnownNames)</p>
|
||||
@ -51,7 +56,7 @@
|
||||
<div class="location-evidence">
|
||||
@foreach (var evidence in candidate.Evidence.Take(3))
|
||||
{
|
||||
<blockquote><strong>@evidence.Label:</strong> @evidence.EvidenceText</blockquote>
|
||||
<blockquote><strong>@evidence.Label</strong><span>@evidence.EvidenceText</span></blockquote>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@ -119,7 +124,7 @@
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<div class="onboarding-actions location-review-actions">
|
||||
<button class="btn btn-secondary" type="submit" name="intent" value="save">Save choices</button>
|
||||
<button class="btn btn-outline-secondary" type="submit" name="intent" value="skip">Skip locations</button>
|
||||
<button class="btn btn-primary" type="submit" name="intent" value="continue">@Model.ContinueButtonText</button>
|
||||
|
||||
@ -31,8 +31,8 @@
|
||||
var requestedCharacterPage = ViewData["CharacterReviewPage"] is int requestedPage ? requestedPage : 1;
|
||||
var characterPage = Math.Clamp(requestedCharacterPage, 1, characterReviewPageCount);
|
||||
var currentCharacters = primaryCharacters.Skip((characterPage - 1) * characterPageSize).Take(characterPageSize).ToList();
|
||||
var currentStep = isCharacterStep ? 9 : 7;
|
||||
const int totalSteps = 10;
|
||||
var currentStep = isCharacterStep ? 10 : 7;
|
||||
const int totalSteps = 11;
|
||||
var characterPageTitle = $"Review Characters {characterPage} of {primaryCharacterPageCount}";
|
||||
var duplicateCanonicalNames = primaryCharacters
|
||||
.Where(candidate => candidate.Include && string.IsNullOrWhiteSpace(candidate.AliasTargetTemporaryCharacterKey))
|
||||
|
||||
@ -37,8 +37,9 @@
|
||||
new("Connect Word", 6),
|
||||
new("Review Chapters", 7),
|
||||
new("Detect Scenes", 8),
|
||||
new("Review Characters", 9),
|
||||
new("Complete", 10)
|
||||
new("Review Locations", 9),
|
||||
new("Review Characters", 10),
|
||||
new("Complete", 11)
|
||||
];
|
||||
|
||||
private static string StepClass(int order, int currentStep)
|
||||
|
||||
@ -747,6 +747,153 @@
|
||||
color: var(--bs-secondary-color);
|
||||
}
|
||||
|
||||
.onboarding-location-review-panel {
|
||||
width: min(1240px, 100%);
|
||||
}
|
||||
|
||||
.onboarding-location-review-panel .review-summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: .75rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.onboarding-location-review-panel .review-summary-grid div {
|
||||
display: grid;
|
||||
gap: .15rem;
|
||||
padding: .85rem 1rem;
|
||||
border: 1px solid rgba(31, 42, 68, .1);
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, .58);
|
||||
}
|
||||
|
||||
.onboarding-location-review-panel .metric-label {
|
||||
color: var(--bs-secondary-color);
|
||||
font-size: .78rem;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.onboarding-location-review-panel .review-summary-grid strong {
|
||||
font-size: 1.45rem;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.location-review-list {
|
||||
display: grid;
|
||||
gap: .85rem;
|
||||
}
|
||||
|
||||
.location-review-row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(18rem, .95fr) minmax(28rem, 1.35fr);
|
||||
gap: 1rem;
|
||||
align-items: start;
|
||||
border: 1px solid rgba(31, 42, 68, .12);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
background: rgba(255, 255, 255, .62);
|
||||
}
|
||||
|
||||
.location-review-title-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: .75rem;
|
||||
}
|
||||
|
||||
.location-review-title-row h2 {
|
||||
margin: 0;
|
||||
font-size: 1.25rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.location-review-title-row span {
|
||||
flex: 0 0 auto;
|
||||
color: var(--bs-secondary-color);
|
||||
font-size: .78rem;
|
||||
font-weight: 800;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.location-review-main > p {
|
||||
margin: .3rem 0 0;
|
||||
color: var(--bs-secondary-color);
|
||||
}
|
||||
|
||||
.location-evidence {
|
||||
display: grid;
|
||||
gap: .45rem;
|
||||
margin-top: .75rem;
|
||||
}
|
||||
|
||||
.location-evidence blockquote {
|
||||
display: grid;
|
||||
gap: .25rem;
|
||||
margin: 0;
|
||||
border-left: 3px solid rgba(47, 111, 99, .34);
|
||||
border-radius: 6px;
|
||||
padding: .55rem .65rem;
|
||||
background: rgba(47, 111, 99, .06);
|
||||
}
|
||||
|
||||
.location-evidence strong {
|
||||
color: var(--bs-body-color);
|
||||
font-size: .78rem;
|
||||
}
|
||||
|
||||
.location-evidence span {
|
||||
color: var(--bs-secondary-color);
|
||||
font-size: .9rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.location-review-controls {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: .75rem;
|
||||
}
|
||||
|
||||
.location-review-controls label {
|
||||
display: grid;
|
||||
gap: .3rem;
|
||||
margin: 0;
|
||||
color: var(--bs-secondary-color);
|
||||
font-size: .82rem;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.location-review-controls input,
|
||||
.location-review-controls select {
|
||||
width: 100%;
|
||||
min-height: 2.35rem;
|
||||
border: 1px solid rgba(31, 42, 68, .18);
|
||||
border-radius: 6px;
|
||||
padding: .45rem .6rem;
|
||||
background-color: var(--bs-body-bg);
|
||||
color: var(--bs-body-color);
|
||||
font-size: .95rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.location-review-controls input:focus,
|
||||
.location-review-controls select:focus {
|
||||
border-color: var(--bs-primary);
|
||||
box-shadow: 0 0 0 .2rem rgba(47, 111, 99, .16);
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.location-review-actions {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
z-index: 2;
|
||||
margin: 1rem calc(clamp(1.25rem, 3vw, 2.5rem) * -1) calc(clamp(1.25rem, 3vw, 2.5rem) * -1);
|
||||
border-top: 1px solid rgba(31, 42, 68, .1);
|
||||
padding: 1rem clamp(1.25rem, 3vw, 2.5rem);
|
||||
background: rgba(255, 255, 255, .92);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
[data-story-intelligence-onboarding] .onboarding-review-counts {
|
||||
position: static;
|
||||
margin-bottom: 1rem;
|
||||
@ -2132,6 +2279,27 @@ summary.story-review-chapter-heading {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.onboarding-location-review-panel .review-summary-grid,
|
||||
.location-review-row,
|
||||
.location-review-controls {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.location-review-title-row {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
gap: .35rem;
|
||||
}
|
||||
|
||||
.location-review-actions {
|
||||
position: static;
|
||||
justify-content: stretch;
|
||||
}
|
||||
|
||||
.location-review-actions .btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.onboarding-companion-details {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user