Phase 12J: Warning Investigation Workflow Improvements.
This commit is contained in:
parent
6a2aeeea90
commit
ecc8d3c76a
@ -8,8 +8,15 @@ namespace PlotLine.Controllers;
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public sealed class ContinuityExplorerController(IStoryStateService storyState) : Controller
|
public sealed class ContinuityExplorerController(IStoryStateService storyState) : Controller
|
||||||
{
|
{
|
||||||
public async Task<IActionResult> Index([FromQuery] ContinuityFilter filter)
|
public async Task<IActionResult> Index(
|
||||||
|
[FromQuery] ContinuityFilter filter,
|
||||||
|
[FromQuery] string? mode,
|
||||||
|
[FromQuery] int? characterId,
|
||||||
|
[FromQuery] int? assetId,
|
||||||
|
[FromQuery] int? locationId,
|
||||||
|
[FromQuery] int? sceneId)
|
||||||
{
|
{
|
||||||
|
ApplyDeepLinkAliases(filter, mode, characterId, assetId, locationId, sceneId);
|
||||||
if (filter.ProjectID == 0)
|
if (filter.ProjectID == 0)
|
||||||
{
|
{
|
||||||
return BadRequest("ProjectID is required.");
|
return BadRequest("ProjectID is required.");
|
||||||
@ -25,4 +32,55 @@ public sealed class ContinuityExplorerController(IStoryStateService storyState)
|
|||||||
{
|
{
|
||||||
return RedirectToAction(nameof(Index), filter);
|
return RedirectToAction(nameof(Index), filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ApplyDeepLinkAliases(ContinuityFilter filter, string? mode, int? characterId, int? assetId, int? locationId, int? sceneId)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(mode))
|
||||||
|
{
|
||||||
|
filter.DisplayMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasFriendlyEntityFilter = characterId.HasValue || assetId.HasValue || locationId.HasValue;
|
||||||
|
if (hasFriendlyEntityFilter)
|
||||||
|
{
|
||||||
|
filter.EntityTypes = [];
|
||||||
|
if (characterId.HasValue)
|
||||||
|
{
|
||||||
|
filter.EntityTypes.Add("Characters");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assetId.HasValue)
|
||||||
|
{
|
||||||
|
filter.EntityTypes.Add("Assets");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locationId.HasValue || string.Equals(filter.DisplayMode, "LocationActivity", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
filter.EntityTypes.Add("Locations");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (characterId.HasValue && !filter.CharacterIDs.Contains(characterId.Value))
|
||||||
|
{
|
||||||
|
filter.CharacterIDs.Add(characterId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assetId.HasValue && !filter.AssetIDs.Contains(assetId.Value))
|
||||||
|
{
|
||||||
|
filter.AssetIDs.Add(assetId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locationId.HasValue && !filter.LocationIDs.Contains(locationId.Value))
|
||||||
|
{
|
||||||
|
filter.LocationIDs.Add(locationId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sceneId.HasValue && !filter.StartSceneID.HasValue && !filter.EndSceneID.HasValue && !filter.SelectedSceneID.HasValue)
|
||||||
|
{
|
||||||
|
filter.SceneRangeMode = "Custom";
|
||||||
|
filter.StartSceneID = sceneId.Value;
|
||||||
|
filter.EndSceneID = sceneId.Value;
|
||||||
|
filter.SelectedSceneID = sceneId.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3029,11 +3029,17 @@ public sealed class StoryStateService(
|
|||||||
warning.KnowledgeDescription = knowledgeDescription;
|
warning.KnowledgeDescription = knowledgeDescription;
|
||||||
warning.PreviousKnowledgeState = previous.Item.KnowledgeStateName;
|
warning.PreviousKnowledgeState = previous.Item.KnowledgeStateName;
|
||||||
warning.CurrentKnowledgeState = current.Item.KnowledgeStateName;
|
warning.CurrentKnowledgeState = current.Item.KnowledgeStateName;
|
||||||
|
var previousSceneContext = context.SceneContexts.GetValueOrDefault(previous.Item.SceneID);
|
||||||
|
var currentSceneContext = context.SceneContexts.GetValueOrDefault(current.Item.SceneID);
|
||||||
|
warning.PreviousBookId = previousSceneContext?.BookID;
|
||||||
|
warning.PreviousChapterId = previousSceneContext?.ChapterID;
|
||||||
warning.PreviousSceneId = previous.Item.SceneID;
|
warning.PreviousSceneId = previous.Item.SceneID;
|
||||||
warning.PreviousSceneDisplayName = context.SceneContexts.GetValueOrDefault(previous.Item.SceneID)?.SceneDisplayName
|
warning.PreviousSceneDisplayName = previousSceneContext?.SceneDisplayName
|
||||||
?? context.SceneLabels.GetValueOrDefault(previous.Item.SceneID, SceneLabel(previous.Item.SceneNumber, previous.Item.SceneTitle));
|
?? context.SceneLabels.GetValueOrDefault(previous.Item.SceneID, SceneLabel(previous.Item.SceneNumber, previous.Item.SceneTitle));
|
||||||
|
warning.CurrentBookId = currentSceneContext?.BookID;
|
||||||
|
warning.CurrentChapterId = currentSceneContext?.ChapterID;
|
||||||
warning.CurrentSceneId = current.Item.SceneID;
|
warning.CurrentSceneId = current.Item.SceneID;
|
||||||
warning.CurrentSceneDisplayName = context.SceneContexts.GetValueOrDefault(current.Item.SceneID)?.SceneDisplayName
|
warning.CurrentSceneDisplayName = currentSceneContext?.SceneDisplayName
|
||||||
?? context.SceneLabels.GetValueOrDefault(current.Item.SceneID, SceneLabel(current.Item.SceneNumber, current.Item.SceneTitle));
|
?? context.SceneLabels.GetValueOrDefault(current.Item.SceneID, SceneLabel(current.Item.SceneNumber, current.Item.SceneTitle));
|
||||||
warnings.Add(warning);
|
warnings.Add(warning);
|
||||||
}
|
}
|
||||||
@ -3218,6 +3224,8 @@ public sealed class StoryStateService(
|
|||||||
Message = message,
|
Message = message,
|
||||||
CharacterID = characterId,
|
CharacterID = characterId,
|
||||||
AssetID = assetId,
|
AssetID = assetId,
|
||||||
|
BookID = sceneContext?.BookID,
|
||||||
|
ChapterID = sceneContext?.ChapterID,
|
||||||
SceneID = sceneId,
|
SceneID = sceneId,
|
||||||
SceneDisplayName = sceneContext?.SceneDisplayName ?? (sceneId.HasValue ? context.SceneLabels.GetValueOrDefault(sceneId.Value, string.Empty) : string.Empty),
|
SceneDisplayName = sceneContext?.SceneDisplayName ?? (sceneId.HasValue ? context.SceneLabels.GetValueOrDefault(sceneId.Value, string.Empty) : string.Empty),
|
||||||
BookDisplayName = sceneContext?.BookDisplayName ?? string.Empty,
|
BookDisplayName = sceneContext?.BookDisplayName ?? string.Empty,
|
||||||
@ -4008,7 +4016,10 @@ public sealed class ContinuityValidationService(
|
|||||||
.Where(x => !chapterId.HasValue || x.ChapterID == chapterId.Value)
|
.Where(x => !chapterId.HasValue || x.ChapterID == chapterId.Value)
|
||||||
.ToList();
|
.ToList();
|
||||||
var continuityWarnings = await storyState.GetContinuityWarningsAsync(projectId, BuildWarningContinuityFilter(projectId, bookId, chapterId, sceneId));
|
var continuityWarnings = await storyState.GetContinuityWarningsAsync(projectId, BuildWarningContinuityFilter(projectId, bookId, chapterId, sceneId));
|
||||||
var dashboardWarnings = rows.Select(ToProjectWarning).Concat(continuityWarnings.Select(ToProjectWarning)).ToList();
|
var booksById = projectBooks.ToDictionary(x => x.BookID);
|
||||||
|
var chaptersById = projectChapters.ToDictionary(x => x.ChapterID);
|
||||||
|
var dashboardWarnings = rows.Select(x => ToProjectWarning(x, booksById, chaptersById)).Concat(continuityWarnings.Select(ToProjectWarning)).ToList();
|
||||||
|
ApplyWarningDisplayContext(dashboardWarnings, bookId, chapterId, booksById, chaptersById);
|
||||||
var availableWarnings = dashboardWarnings.ToList();
|
var availableWarnings = dashboardWarnings.ToList();
|
||||||
var hasAnyWarnings = availableWarnings.Any();
|
var hasAnyWarnings = availableWarnings.Any();
|
||||||
|
|
||||||
@ -4083,8 +4094,20 @@ public sealed class ContinuityValidationService(
|
|||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ProjectWarningViewModel ToProjectWarning(ContinuityWarning warning)
|
private static ProjectWarningViewModel ToProjectWarning(
|
||||||
|
ContinuityWarning warning,
|
||||||
|
IReadOnlyDictionary<int, Book> booksById,
|
||||||
|
IReadOnlyDictionary<int, Chapter> chaptersById)
|
||||||
{
|
{
|
||||||
|
var bookDisplayName = warning.BookID.HasValue && booksById.TryGetValue(warning.BookID.Value, out var book)
|
||||||
|
? $"Book {book.BookNumber:g}: {book.BookTitle}"
|
||||||
|
: warning.BookTitle ?? string.Empty;
|
||||||
|
var chapterDisplayName = warning.ChapterID.HasValue && chaptersById.TryGetValue(warning.ChapterID.Value, out var chapter)
|
||||||
|
? $"Chapter {chapter.ChapterNumber:g}: {chapter.ChapterTitle}"
|
||||||
|
: warning.ChapterNumber.HasValue
|
||||||
|
? $"Chapter {warning.ChapterNumber:g}: {warning.ChapterTitle}"
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
return new ProjectWarningViewModel
|
return new ProjectWarningViewModel
|
||||||
{
|
{
|
||||||
Source = "Persisted",
|
Source = "Persisted",
|
||||||
@ -4096,11 +4119,9 @@ public sealed class ContinuityValidationService(
|
|||||||
Message = warning.Message,
|
Message = warning.Message,
|
||||||
Details = warning.Details,
|
Details = warning.Details,
|
||||||
BookID = warning.BookID,
|
BookID = warning.BookID,
|
||||||
BookDisplayName = string.IsNullOrWhiteSpace(warning.BookTitle) ? string.Empty : warning.BookTitle,
|
BookDisplayName = bookDisplayName,
|
||||||
ChapterID = warning.ChapterID,
|
ChapterID = warning.ChapterID,
|
||||||
ChapterDisplayName = warning.ChapterNumber.HasValue
|
ChapterDisplayName = chapterDisplayName,
|
||||||
? $"Ch {warning.ChapterNumber:g}: {warning.ChapterTitle}"
|
|
||||||
: string.Empty,
|
|
||||||
SceneID = warning.SceneID,
|
SceneID = warning.SceneID,
|
||||||
SceneDisplayName = warning.SceneID.HasValue
|
SceneDisplayName = warning.SceneID.HasValue
|
||||||
? SceneLabel(warning.SceneNumber ?? 0, warning.SceneTitle ?? string.Empty)
|
? SceneLabel(warning.SceneNumber ?? 0, warning.SceneTitle ?? string.Empty)
|
||||||
@ -4122,7 +4143,9 @@ public sealed class ContinuityValidationService(
|
|||||||
Category = WarningCategoryForGenerated(warning),
|
Category = WarningCategoryForGenerated(warning),
|
||||||
Severity = warning.Severity,
|
Severity = warning.Severity,
|
||||||
Message = warning.Message,
|
Message = warning.Message,
|
||||||
|
BookID = warning.BookID,
|
||||||
BookDisplayName = warning.BookDisplayName,
|
BookDisplayName = warning.BookDisplayName,
|
||||||
|
ChapterID = warning.ChapterID,
|
||||||
ChapterDisplayName = warning.ChapterDisplayName,
|
ChapterDisplayName = warning.ChapterDisplayName,
|
||||||
SceneID = warning.SceneID,
|
SceneID = warning.SceneID,
|
||||||
SceneDisplayName = warning.SceneDisplayName,
|
SceneDisplayName = warning.SceneDisplayName,
|
||||||
@ -4138,10 +4161,16 @@ public sealed class ContinuityValidationService(
|
|||||||
KnowledgeDescription = warning.KnowledgeDescription,
|
KnowledgeDescription = warning.KnowledgeDescription,
|
||||||
PreviousKnowledgeState = warning.PreviousKnowledgeState,
|
PreviousKnowledgeState = warning.PreviousKnowledgeState,
|
||||||
CurrentKnowledgeState = warning.CurrentKnowledgeState,
|
CurrentKnowledgeState = warning.CurrentKnowledgeState,
|
||||||
|
PreviousBookId = warning.PreviousBookId,
|
||||||
|
PreviousChapterId = warning.PreviousChapterId,
|
||||||
PreviousSceneId = warning.PreviousSceneId,
|
PreviousSceneId = warning.PreviousSceneId,
|
||||||
PreviousSceneDisplayName = warning.PreviousSceneDisplayName,
|
PreviousSceneDisplayName = warning.PreviousSceneDisplayName,
|
||||||
|
PreviousContextSceneDisplayName = warning.PreviousContextSceneDisplayName,
|
||||||
|
CurrentBookId = warning.CurrentBookId,
|
||||||
|
CurrentChapterId = warning.CurrentChapterId,
|
||||||
CurrentSceneId = warning.CurrentSceneId,
|
CurrentSceneId = warning.CurrentSceneId,
|
||||||
CurrentSceneDisplayName = warning.CurrentSceneDisplayName,
|
CurrentSceneDisplayName = warning.CurrentSceneDisplayName,
|
||||||
|
CurrentContextSceneDisplayName = warning.CurrentContextSceneDisplayName,
|
||||||
EstablishedSceneId = warning.EstablishedSceneId,
|
EstablishedSceneId = warning.EstablishedSceneId,
|
||||||
EstablishedSceneDisplayName = warning.EstablishedSceneDisplayName,
|
EstablishedSceneDisplayName = warning.EstablishedSceneDisplayName,
|
||||||
ReferencedSceneId = warning.ReferencedSceneId,
|
ReferencedSceneId = warning.ReferencedSceneId,
|
||||||
@ -4150,6 +4179,124 @@ public sealed class ContinuityValidationService(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ApplyWarningDisplayContext(
|
||||||
|
List<ProjectWarningViewModel> warnings,
|
||||||
|
int? scopedBookId,
|
||||||
|
int? scopedChapterId,
|
||||||
|
IReadOnlyDictionary<int, Book> booksById,
|
||||||
|
IReadOnlyDictionary<int, Chapter> chaptersById)
|
||||||
|
{
|
||||||
|
foreach (var warning in warnings)
|
||||||
|
{
|
||||||
|
warning.ContextSceneDisplayName = FormatWarningSceneContext(
|
||||||
|
warning.BookID,
|
||||||
|
warning.BookDisplayName,
|
||||||
|
warning.ChapterID,
|
||||||
|
warning.ChapterDisplayName,
|
||||||
|
warning.SceneDisplayName,
|
||||||
|
scopedBookId,
|
||||||
|
scopedChapterId,
|
||||||
|
booksById,
|
||||||
|
chaptersById);
|
||||||
|
warning.PreviousContextSceneDisplayName = FormatWarningSceneContext(
|
||||||
|
warning.PreviousBookId,
|
||||||
|
string.Empty,
|
||||||
|
warning.PreviousChapterId,
|
||||||
|
string.Empty,
|
||||||
|
warning.PreviousSceneDisplayName,
|
||||||
|
scopedBookId,
|
||||||
|
scopedChapterId,
|
||||||
|
booksById,
|
||||||
|
chaptersById);
|
||||||
|
warning.CurrentContextSceneDisplayName = FormatWarningSceneContext(
|
||||||
|
warning.CurrentBookId,
|
||||||
|
string.Empty,
|
||||||
|
warning.CurrentChapterId,
|
||||||
|
string.Empty,
|
||||||
|
warning.CurrentSceneDisplayName,
|
||||||
|
scopedBookId,
|
||||||
|
scopedChapterId,
|
||||||
|
booksById,
|
||||||
|
chaptersById);
|
||||||
|
warning.EstablishedContextSceneDisplayName = string.IsNullOrWhiteSpace(warning.EstablishedSceneDisplayName)
|
||||||
|
? string.Empty
|
||||||
|
: warning.EstablishedSceneDisplayName;
|
||||||
|
warning.ReferencedContextSceneDisplayName = string.IsNullOrWhiteSpace(warning.ReferencedSceneDisplayName)
|
||||||
|
? string.Empty
|
||||||
|
: warning.ReferencedSceneDisplayName;
|
||||||
|
ApplyInvestigationTarget(warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatWarningSceneContext(
|
||||||
|
int? bookId,
|
||||||
|
string bookDisplayName,
|
||||||
|
int? chapterId,
|
||||||
|
string chapterDisplayName,
|
||||||
|
string sceneDisplayName,
|
||||||
|
int? scopedBookId,
|
||||||
|
int? scopedChapterId,
|
||||||
|
IReadOnlyDictionary<int, Book> booksById,
|
||||||
|
IReadOnlyDictionary<int, Chapter> chaptersById)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(sceneDisplayName))
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(bookDisplayName) && bookId.HasValue && booksById.TryGetValue(bookId.Value, out var book))
|
||||||
|
{
|
||||||
|
bookDisplayName = $"Book {book.BookNumber:g}: {book.BookTitle}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(chapterDisplayName) && chapterId.HasValue && chaptersById.TryGetValue(chapterId.Value, out var chapter))
|
||||||
|
{
|
||||||
|
chapterDisplayName = $"Chapter {chapter.ChapterNumber:g}: {chapter.ChapterTitle}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scopedChapterId.HasValue)
|
||||||
|
{
|
||||||
|
return sceneDisplayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scopedBookId.HasValue || (bookId.HasValue && scopedBookId == bookId))
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(chapterDisplayName)
|
||||||
|
? sceneDisplayName
|
||||||
|
: $"{chapterDisplayName} • {sceneDisplayName}";
|
||||||
|
}
|
||||||
|
|
||||||
|
var parts = new List<string>();
|
||||||
|
if (!string.IsNullOrWhiteSpace(bookDisplayName))
|
||||||
|
{
|
||||||
|
parts.Add(bookDisplayName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(chapterDisplayName))
|
||||||
|
{
|
||||||
|
parts.Add(chapterDisplayName);
|
||||||
|
}
|
||||||
|
|
||||||
|
parts.Add(sceneDisplayName);
|
||||||
|
return string.Join(" • ", parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ApplyInvestigationTarget(ProjectWarningViewModel warning)
|
||||||
|
{
|
||||||
|
if (warning.Source != "Generated")
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
warning.CanInvestigate = true;
|
||||||
|
warning.InvestigationDisplayMode = warning.WarningTypeDisplayName switch
|
||||||
|
{
|
||||||
|
"Multiple Character Locations" => "LocationActivity",
|
||||||
|
_ => "Journey"
|
||||||
|
};
|
||||||
|
warning.InvestigationSceneId = warning.CurrentSceneId ?? warning.ReferencedSceneId ?? warning.SceneID;
|
||||||
|
}
|
||||||
|
|
||||||
private static string WarningCategoryForPersisted(ContinuityWarning warning)
|
private static string WarningCategoryForPersisted(ContinuityWarning warning)
|
||||||
{
|
{
|
||||||
return warning.EntityType switch
|
return warning.EntityType switch
|
||||||
|
|||||||
@ -325,8 +325,11 @@ public sealed class ContinuityWarningViewModel
|
|||||||
public int? CharacterID { get; set; }
|
public int? CharacterID { get; set; }
|
||||||
public string CharacterName { get; set; } = string.Empty;
|
public string CharacterName { get; set; } = string.Empty;
|
||||||
public int? AssetID { get; set; }
|
public int? AssetID { get; set; }
|
||||||
|
public int? BookID { get; set; }
|
||||||
|
public int? ChapterID { get; set; }
|
||||||
public int? SceneID { get; set; }
|
public int? SceneID { get; set; }
|
||||||
public string SceneDisplayName { get; set; } = string.Empty;
|
public string SceneDisplayName { get; set; } = string.Empty;
|
||||||
|
public string ContextSceneDisplayName { get; set; } = string.Empty;
|
||||||
public string BookDisplayName { get; set; } = string.Empty;
|
public string BookDisplayName { get; set; } = string.Empty;
|
||||||
public string ChapterDisplayName { get; set; } = string.Empty;
|
public string ChapterDisplayName { get; set; } = string.Empty;
|
||||||
public bool IsAcknowledged { get; set; }
|
public bool IsAcknowledged { get; set; }
|
||||||
@ -336,14 +339,25 @@ public sealed class ContinuityWarningViewModel
|
|||||||
public string KnowledgeDescription { get; set; } = string.Empty;
|
public string KnowledgeDescription { get; set; } = string.Empty;
|
||||||
public string PreviousKnowledgeState { get; set; } = string.Empty;
|
public string PreviousKnowledgeState { get; set; } = string.Empty;
|
||||||
public string CurrentKnowledgeState { get; set; } = string.Empty;
|
public string CurrentKnowledgeState { get; set; } = string.Empty;
|
||||||
|
public int? PreviousBookId { get; set; }
|
||||||
|
public int? PreviousChapterId { get; set; }
|
||||||
public int? PreviousSceneId { get; set; }
|
public int? PreviousSceneId { get; set; }
|
||||||
public string PreviousSceneDisplayName { get; set; } = string.Empty;
|
public string PreviousSceneDisplayName { get; set; } = string.Empty;
|
||||||
|
public string PreviousContextSceneDisplayName { get; set; } = string.Empty;
|
||||||
|
public int? CurrentBookId { get; set; }
|
||||||
|
public int? CurrentChapterId { get; set; }
|
||||||
public int? CurrentSceneId { get; set; }
|
public int? CurrentSceneId { get; set; }
|
||||||
public string CurrentSceneDisplayName { get; set; } = string.Empty;
|
public string CurrentSceneDisplayName { get; set; } = string.Empty;
|
||||||
|
public string CurrentContextSceneDisplayName { get; set; } = string.Empty;
|
||||||
public int? EstablishedSceneId { get; set; }
|
public int? EstablishedSceneId { get; set; }
|
||||||
public string EstablishedSceneDisplayName { get; set; } = string.Empty;
|
public string EstablishedSceneDisplayName { get; set; } = string.Empty;
|
||||||
|
public string EstablishedContextSceneDisplayName { get; set; } = string.Empty;
|
||||||
public int? ReferencedSceneId { get; set; }
|
public int? ReferencedSceneId { get; set; }
|
||||||
public string ReferencedSceneDisplayName { get; set; } = string.Empty;
|
public string ReferencedSceneDisplayName { get; set; } = string.Empty;
|
||||||
|
public string ReferencedContextSceneDisplayName { get; set; } = string.Empty;
|
||||||
|
public string InvestigationDisplayMode { get; set; } = string.Empty;
|
||||||
|
public int? InvestigationSceneId { get; set; }
|
||||||
|
public bool CanInvestigate { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class CharacterJourneyViewModel
|
public sealed class CharacterJourneyViewModel
|
||||||
@ -1685,6 +1699,7 @@ public sealed class ProjectWarningViewModel
|
|||||||
public string ChapterDisplayName { get; set; } = string.Empty;
|
public string ChapterDisplayName { get; set; } = string.Empty;
|
||||||
public int? SceneID { get; set; }
|
public int? SceneID { get; set; }
|
||||||
public string SceneDisplayName { get; set; } = string.Empty;
|
public string SceneDisplayName { get; set; } = string.Empty;
|
||||||
|
public string ContextSceneDisplayName { get; set; } = string.Empty;
|
||||||
public int? CharacterID { get; set; }
|
public int? CharacterID { get; set; }
|
||||||
public string CharacterName { get; set; } = string.Empty;
|
public string CharacterName { get; set; } = string.Empty;
|
||||||
public int? AssetID { get; set; }
|
public int? AssetID { get; set; }
|
||||||
@ -1699,14 +1714,25 @@ public sealed class ProjectWarningViewModel
|
|||||||
public string KnowledgeDescription { get; set; } = string.Empty;
|
public string KnowledgeDescription { get; set; } = string.Empty;
|
||||||
public string PreviousKnowledgeState { get; set; } = string.Empty;
|
public string PreviousKnowledgeState { get; set; } = string.Empty;
|
||||||
public string CurrentKnowledgeState { get; set; } = string.Empty;
|
public string CurrentKnowledgeState { get; set; } = string.Empty;
|
||||||
|
public int? PreviousBookId { get; set; }
|
||||||
|
public int? PreviousChapterId { get; set; }
|
||||||
public int? PreviousSceneId { get; set; }
|
public int? PreviousSceneId { get; set; }
|
||||||
public string PreviousSceneDisplayName { get; set; } = string.Empty;
|
public string PreviousSceneDisplayName { get; set; } = string.Empty;
|
||||||
|
public string PreviousContextSceneDisplayName { get; set; } = string.Empty;
|
||||||
|
public int? CurrentBookId { get; set; }
|
||||||
|
public int? CurrentChapterId { get; set; }
|
||||||
public int? CurrentSceneId { get; set; }
|
public int? CurrentSceneId { get; set; }
|
||||||
public string CurrentSceneDisplayName { get; set; } = string.Empty;
|
public string CurrentSceneDisplayName { get; set; } = string.Empty;
|
||||||
|
public string CurrentContextSceneDisplayName { get; set; } = string.Empty;
|
||||||
public int? EstablishedSceneId { get; set; }
|
public int? EstablishedSceneId { get; set; }
|
||||||
public string EstablishedSceneDisplayName { get; set; } = string.Empty;
|
public string EstablishedSceneDisplayName { get; set; } = string.Empty;
|
||||||
|
public string EstablishedContextSceneDisplayName { get; set; } = string.Empty;
|
||||||
public int? ReferencedSceneId { get; set; }
|
public int? ReferencedSceneId { get; set; }
|
||||||
public string ReferencedSceneDisplayName { get; set; } = string.Empty;
|
public string ReferencedSceneDisplayName { get; set; } = string.Empty;
|
||||||
|
public string ReferencedContextSceneDisplayName { get; set; } = string.Empty;
|
||||||
|
public string InvestigationDisplayMode { get; set; } = string.Empty;
|
||||||
|
public int? InvestigationSceneId { get; set; }
|
||||||
|
public bool CanInvestigate { get; set; }
|
||||||
public DateTime LastDetectedDate { get; set; }
|
public DateTime LastDetectedDate { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -183,28 +183,28 @@
|
|||||||
{
|
{
|
||||||
<small class="text-muted d-block">
|
<small class="text-muted d-block">
|
||||||
Previous:
|
Previous:
|
||||||
<a asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-selectedSceneId="@warning.PreviousSceneId">@warning.PreviousSceneDisplayName</a>
|
<a asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-selectedSceneId="@warning.PreviousSceneId">@warning.PreviousContextSceneDisplayName</a>
|
||||||
</small>
|
</small>
|
||||||
}
|
}
|
||||||
@if (warning.CurrentSceneId.HasValue)
|
@if (warning.CurrentSceneId.HasValue)
|
||||||
{
|
{
|
||||||
<small class="text-muted d-block">
|
<small class="text-muted d-block">
|
||||||
Current:
|
Current:
|
||||||
<a asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-selectedSceneId="@warning.CurrentSceneId">@warning.CurrentSceneDisplayName</a>
|
<a asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-selectedSceneId="@warning.CurrentSceneId">@warning.CurrentContextSceneDisplayName</a>
|
||||||
</small>
|
</small>
|
||||||
}
|
}
|
||||||
@if (warning.EstablishedSceneId.HasValue)
|
@if (warning.EstablishedSceneId.HasValue)
|
||||||
{
|
{
|
||||||
<small class="text-muted d-block">
|
<small class="text-muted d-block">
|
||||||
Established:
|
Established:
|
||||||
<a asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-selectedSceneId="@warning.EstablishedSceneId">@warning.EstablishedSceneDisplayName</a>
|
<a asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-selectedSceneId="@warning.EstablishedSceneId">@(string.IsNullOrWhiteSpace(warning.EstablishedContextSceneDisplayName) ? warning.EstablishedSceneDisplayName : warning.EstablishedContextSceneDisplayName)</a>
|
||||||
</small>
|
</small>
|
||||||
}
|
}
|
||||||
@if (warning.ReferencedSceneId.HasValue)
|
@if (warning.ReferencedSceneId.HasValue)
|
||||||
{
|
{
|
||||||
<small class="text-muted d-block">
|
<small class="text-muted d-block">
|
||||||
Earlier reference:
|
Earlier reference:
|
||||||
<a asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-selectedSceneId="@warning.ReferencedSceneId">@warning.ReferencedSceneDisplayName</a>
|
<a asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-selectedSceneId="@warning.ReferencedSceneId">@(string.IsNullOrWhiteSpace(warning.ReferencedContextSceneDisplayName) ? warning.ReferencedSceneDisplayName : warning.ReferencedContextSceneDisplayName)</a>
|
||||||
</small>
|
</small>
|
||||||
}
|
}
|
||||||
@if (warning.IsAcknowledged && !string.IsNullOrWhiteSpace(warning.AcknowledgementNotes))
|
@if (warning.IsAcknowledged && !string.IsNullOrWhiteSpace(warning.AcknowledgementNotes))
|
||||||
@ -217,7 +217,7 @@
|
|||||||
<td>
|
<td>
|
||||||
@if (warning.SceneID.HasValue)
|
@if (warning.SceneID.HasValue)
|
||||||
{
|
{
|
||||||
<a asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-selectedSceneId="@warning.SceneID">@warning.SceneDisplayName</a>
|
<a asp-controller="Timeline" asp-action="Index" asp-route-projectId="@Model.Project.ProjectID" asp-route-selectedSceneId="@warning.SceneID">@warning.ContextSceneDisplayName</a>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -239,6 +239,17 @@
|
|||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
@if (warning.CanInvestigate)
|
||||||
|
{
|
||||||
|
<a class="btn btn-outline-primary btn-sm"
|
||||||
|
asp-controller="ContinuityExplorer"
|
||||||
|
asp-action="Index"
|
||||||
|
asp-route-projectId="@Model.Project.ProjectID"
|
||||||
|
asp-route-mode="@warning.InvestigationDisplayMode"
|
||||||
|
asp-route-characterId="@warning.CharacterID"
|
||||||
|
asp-route-assetId="@warning.AssetID"
|
||||||
|
asp-route-sceneId="@warning.InvestigationSceneId">Investigate</a>
|
||||||
|
}
|
||||||
@if (warning.Source == "Persisted" && warning.ContinuityWarningID.HasValue)
|
@if (warning.Source == "Persisted" && warning.ContinuityWarningID.HasValue)
|
||||||
{
|
{
|
||||||
@if (warning.IsDismissed || warning.IsIntentional)
|
@if (warning.IsDismissed || warning.IsIntentional)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user