Split advanced diagnostics from cell editor

This commit is contained in:
2026-03-15 02:17:40 +01:00
parent 641e33f811
commit 96fa9370f4
3 changed files with 265 additions and 7 deletions

View File

@@ -1,6 +1,7 @@
@using System
@using System.Collections.Generic
@using System.Linq
@using System.Text.Json
@using RolemasterDb.App.Domain
@using RolemasterDb.App.Features
@@ -94,12 +95,7 @@
</div>
@if (Model.ValidationMessages.Count > 0)
{
<div class="critical-editor-validation-list">
@foreach (var message in Model.ValidationMessages)
{
<p class="critical-editor-validation-item">@message</p>
}
</div>
<p class="muted critical-editor-advanced-hint">@GetParserNoteSummary(Model.ValidationMessages.Count)</p>
}
<div class="field-shell">
<label>Result Text Override</label>
@@ -228,6 +224,94 @@
}
}
</section>
<section class="critical-editor-section critical-editor-diagnostics-section">
<details class="critical-editor-advanced">
<summary class="critical-editor-advanced-summary">
<span>Advanced Diagnostics</span>
<span class="critical-editor-advanced-meta">@GetAdvancedSummary(Model)</span>
</summary>
<div class="critical-editor-advanced-body">
<div class="critical-editor-card nested">
<div class="critical-editor-card-header">
<div>
<strong>Parser Metadata</strong>
<p class="muted critical-editor-inline-copy">Last loaded or re-parsed parser result.</p>
</div>
</div>
<dl class="critical-editor-diagnostic-grid">
<div>
<dt>Parse Status</dt>
<dd>@Model.ParseStatus</dd>
</div>
<div>
<dt>Raw Affix Text</dt>
<dd>@(string.IsNullOrWhiteSpace(Model.RawAffixText) ? "—" : Model.RawAffixText)</dd>
</div>
</dl>
@if (Model.ValidationMessages.Count > 0)
{
<div class="critical-editor-validation-list">
@foreach (var message in Model.ValidationMessages)
{
<p class="critical-editor-validation-item">@message</p>
}
</div>
}
<div class="field-shell">
<label>Parsed Effects JSON</label>
<pre class="critical-editor-diagnostic-block">@FormatJson(Model.ParsedJson)</pre>
</div>
</div>
@{
var effectMetadata = GetEffectMetadataRows(Model);
}
@if (effectMetadata.Count > 0)
{
<div class="critical-editor-card nested">
<div class="critical-editor-card-header">
<div>
<strong>Effect Source Metadata</strong>
<p class="muted critical-editor-inline-copy">Stored source markers and labels for the current effect list.</p>
</div>
</div>
<div class="critical-editor-diagnostic-list">
@foreach (var entry in effectMetadata)
{
<div class="critical-editor-diagnostic-item">
<div>
<strong>@entry.Scope</strong>
<p class="muted critical-editor-inline-copy">@entry.EffectLabel</p>
</div>
<div class="critical-editor-diagnostic-values">
<span><strong>Type:</strong> @entry.SourceType</span>
<span><strong>Text:</strong> @(string.IsNullOrWhiteSpace(entry.SourceText) ? "—" : entry.SourceText)</span>
</div>
</div>
}
</div>
</div>
}
<div class="critical-editor-card nested">
<div class="critical-editor-card-header">
<div>
<strong>Current Save Payload</strong>
<p class="muted critical-editor-inline-copy">Request built from the visible editor state, including generated branch internals.</p>
</div>
</div>
<pre class="critical-editor-diagnostic-block">@BuildCurrentSavePayloadJson(Model)</pre>
</div>
</div>
</details>
</section>
</div>
<footer class="critical-editor-footer">
@@ -272,6 +356,11 @@
[Parameter, EditorRequired]
public EventCallback OnSave { get; set; }
private static readonly JsonSerializerOptions DiagnosticJsonOptions = new()
{
WriteIndented = true
};
private async Task HandleBackdropClicked()
{
await OnClose.InvokeAsync();
@@ -393,6 +482,69 @@
effect.SourceType = AffixDisplayMap.TryGet(effect.EffectCode, out _) ? "symbol" : "manual";
}
private static string GetAdvancedSummary(CriticalCellEditorModel model)
{
var noteCount = model.ValidationMessages.Count;
return noteCount == 0 ? "Parser metadata and save payload" : $"{noteCount} parser note{(noteCount == 1 ? string.Empty : "s")}";
}
private static string GetParserNoteSummary(int noteCount) =>
noteCount == 1
? "1 parser note is available under Advanced Diagnostics."
: $"{noteCount} parser notes are available under Advanced Diagnostics.";
private static string FormatJson(string json)
{
if (string.IsNullOrWhiteSpace(json))
{
return "{}";
}
try
{
using var document = JsonDocument.Parse(json);
return JsonSerializer.Serialize(document.RootElement, DiagnosticJsonOptions);
}
catch (JsonException)
{
return json.Trim();
}
}
private static string BuildCurrentSavePayloadJson(CriticalCellEditorModel model) =>
JsonSerializer.Serialize(model.ToRequest(), DiagnosticJsonOptions);
private static List<(string Scope, string EffectLabel, string SourceType, string? SourceText)> GetEffectMetadataRows(CriticalCellEditorModel model)
{
var rows = new List<(string Scope, string EffectLabel, string SourceType, string? SourceText)>();
foreach (var effect in model.Effects)
{
if (ShouldIncludeEffectMetadata(effect))
{
rows.Add(("Base Result", GetEffectLabel(effect), effect.SourceType, effect.SourceText));
}
}
foreach (var branch in model.Branches.OrderBy(item => item.SortOrder))
{
var scope = string.IsNullOrWhiteSpace(branch.ConditionText) ? "Condition" : branch.ConditionText.Trim();
foreach (var effect in branch.Effects)
{
if (ShouldIncludeEffectMetadata(effect))
{
rows.Add((scope, GetEffectLabel(effect), effect.SourceType, effect.SourceText));
}
}
}
return rows;
}
private static bool ShouldIncludeEffectMetadata(CriticalEffectEditorModel effect) =>
!string.IsNullOrWhiteSpace(effect.SourceText) ||
!string.IsNullOrWhiteSpace(effect.SourceType);
private static IReadOnlyList<CriticalEffectLookupResponse> BuildPreviewEffects(IEnumerable<CriticalEffectEditorModel> effects) =>
effects.Select(CreatePreviewEffect).ToList();