Separate critical editor load and save errors

This commit is contained in:
2026-03-14 15:37:20 +01:00
parent 19164736ad
commit 29851ed810
2 changed files with 181 additions and 164 deletions

View File

@@ -204,7 +204,8 @@
Model="editorModel" Model="editorModel"
IsLoading="isEditorLoading" IsLoading="isEditorLoading"
IsSaving="isEditorSaving" IsSaving="isEditorSaving"
ErrorMessage="editorError" LoadErrorMessage="editorLoadError"
SaveErrorMessage="editorSaveError"
OnClose="CloseCellEditorAsync" OnClose="CloseCellEditorAsync"
OnSave="SaveCellEditorAsync" /> OnSave="SaveCellEditorAsync" />
} }
@@ -223,7 +224,8 @@
private bool isEditorOpen; private bool isEditorOpen;
private bool isEditorLoading; private bool isEditorLoading;
private bool isEditorSaving; private bool isEditorSaving;
private string? editorError; private string? editorLoadError;
private string? editorSaveError;
private int? editingResultId; private int? editingResultId;
private CriticalCellEditorModel? editorModel; private CriticalCellEditorModel? editorModel;
@@ -321,7 +323,8 @@
return; return;
} }
editorError = null; editorLoadError = null;
editorSaveError = null;
editorModel = null; editorModel = null;
editingResultId = resultId; editingResultId = resultId;
isEditorSaving = false; isEditorSaving = false;
@@ -333,7 +336,7 @@
var response = await LookupService.GetCriticalCellEditorAsync(selectedTableSlug, resultId); var response = await LookupService.GetCriticalCellEditorAsync(selectedTableSlug, resultId);
if (response is null) if (response is null)
{ {
editorError = "The selected cell could not be loaded for editing."; editorLoadError = "The selected cell could not be loaded for editing.";
editorModel = null; editorModel = null;
return; return;
} }
@@ -342,7 +345,7 @@
} }
catch (Exception exception) catch (Exception exception)
{ {
editorError = exception.Message; editorLoadError = exception.Message;
editorModel = null; editorModel = null;
} }
finally finally
@@ -356,7 +359,8 @@
isEditorOpen = false; isEditorOpen = false;
isEditorLoading = false; isEditorLoading = false;
isEditorSaving = false; isEditorSaving = false;
editorError = null; editorLoadError = null;
editorSaveError = null;
editingResultId = null; editingResultId = null;
editorModel = null; editorModel = null;
await InvokeAsync(StateHasChanged); await InvokeAsync(StateHasChanged);
@@ -370,14 +374,14 @@
} }
isEditorSaving = true; isEditorSaving = true;
editorError = null; editorSaveError = null;
try try
{ {
var response = await LookupService.UpdateCriticalCellAsync(selectedTableSlug, editingResultId.Value, editorModel.ToRequest()); var response = await LookupService.UpdateCriticalCellAsync(selectedTableSlug, editingResultId.Value, editorModel.ToRequest());
if (response is null) if (response is null)
{ {
editorError = "The selected cell could not be saved."; editorSaveError = "The selected cell could not be saved.";
return; return;
} }
@@ -386,7 +390,7 @@
} }
catch (Exception exception) catch (Exception exception)
{ {
editorError = exception.Message; editorSaveError = exception.Message;
} }
finally finally
{ {

View File

@@ -1,10 +1,10 @@
@if (Model is not null) <div class="critical-editor-backdrop" @onclick="HandleBackdropClicked">
{ <div class="critical-editor-dialog" @onclick:stopPropagation="true">
<div class="critical-editor-backdrop" @onclick="HandleBackdropClicked"> <header class="critical-editor-header">
<div class="critical-editor-dialog" @onclick:stopPropagation="true"> <div>
<header class="critical-editor-header"> <span class="eyebrow">Manual Curation</span>
<div> @if (Model is not null)
<span class="eyebrow">@Model.SourceDocument</span> {
<h3 class="panel-title">Edit @Model.TableName</h3> <h3 class="panel-title">Edit @Model.TableName</h3>
<p class="muted critical-editor-meta"> <p class="muted critical-editor-meta">
Roll band <strong>@Model.RollBand</strong>, column <strong>@Model.ColumnLabel</strong> Roll band <strong>@Model.RollBand</strong>, column <strong>@Model.ColumnLabel</strong>
@@ -13,177 +13,187 @@
<span>, group <strong>@Model.GroupLabel</strong></span> <span>, group <strong>@Model.GroupLabel</strong></span>
} }
</p> </p>
</div> }
<button type="button" class="btn btn-link critical-editor-close" @onclick="OnClose">Close</button> else
</header> {
<h3 class="panel-title">Critical Cell Editor</h3>
}
</div>
<button type="button" class="btn btn-link critical-editor-close" @onclick="OnClose">Close</button>
</header>
@if (IsLoading) @if (IsLoading)
{ {
<div class="critical-editor-body">
<p class="muted">Loading editor...</p>
</div>
}
else if (!string.IsNullOrWhiteSpace(LoadErrorMessage))
{
<div class="critical-editor-body">
<p class="error-text critical-editor-error">@LoadErrorMessage</p>
</div>
}
else if (Model is not null)
{
<EditForm Model="Model" OnSubmit="HandleSubmitAsync" class="critical-editor-form">
<div class="critical-editor-body"> <div class="critical-editor-body">
<p class="muted">Loading editor...</p> @if (!string.IsNullOrWhiteSpace(SaveErrorMessage))
</div> {
} <p class="error-text critical-editor-error">@SaveErrorMessage</p>
else }
{
<EditForm Model="Model" OnSubmit="HandleSubmitAsync" class="critical-editor-form"> <section class="critical-editor-section">
<div class="critical-editor-body"> <h4>Base Cell</h4>
@if (!string.IsNullOrWhiteSpace(ErrorMessage)) <div class="field-shell">
<label>Raw Cell Text</label>
<InputTextArea class="input-shell critical-editor-textarea tall" @bind-Value="Model.RawCellText" />
</div>
<div class="field-shell">
<label>Description / Prose</label>
<InputText class="input-shell" @bind-Value="Model.DescriptionText" />
</div>
<div class="field-shell">
<label>Affix Text</label>
<InputText class="input-shell" @bind-Value="Model.RawAffixText" />
</div>
<div class="form-grid">
<div class="field-shell">
<label>Parse Status</label>
<InputText class="input-shell" @bind-Value="Model.ParseStatus" />
</div>
<div class="field-shell">
<label>Parsed Json</label>
<InputTextArea class="input-shell critical-editor-textarea json" @bind-Value="Model.ParsedJson" />
</div>
</div>
</section>
<section class="critical-editor-section">
<div class="critical-editor-section-header">
<h4>Base Effects</h4>
<button type="button" class="btn-ritual" @onclick="AddBaseEffect">Add Effect</button>
</div>
@if (Model.Effects.Count == 0)
{ {
<p class="error-text critical-editor-error">@ErrorMessage</p> <p class="muted">No normalized base effects for this cell.</p>
} }
else
<section class="critical-editor-section"> {
<h4>Base Cell</h4> @for (var index = 0; index < Model.Effects.Count; index++)
<div class="field-shell">
<label>Raw Cell Text</label>
<InputTextArea class="input-shell critical-editor-textarea tall" @bind-Value="Model.RawCellText" />
</div>
<div class="field-shell">
<label>Description / Prose</label>
<InputText class="input-shell" @bind-Value="Model.DescriptionText" />
</div>
<div class="field-shell">
<label>Affix Text</label>
<InputText class="input-shell" @bind-Value="Model.RawAffixText" />
</div>
<div class="form-grid">
<div class="field-shell">
<label>Parse Status</label>
<InputText class="input-shell" @bind-Value="Model.ParseStatus" />
</div>
<div class="field-shell">
<label>Parsed Json</label>
<InputTextArea class="input-shell critical-editor-textarea json" @bind-Value="Model.ParsedJson" />
</div>
</div>
</section>
<section class="critical-editor-section">
<div class="critical-editor-section-header">
<h4>Base Effects</h4>
<button type="button" class="btn-ritual" @onclick="AddBaseEffect">Add Effect</button>
</div>
@if (Model.Effects.Count == 0)
{ {
<p class="muted">No normalized base effects for this cell.</p> var effect = Model.Effects[index];
} <div class="critical-editor-card">
else <div class="critical-editor-card-header">
{ <strong>Effect @(index + 1)</strong>
@for (var index = 0; index < Model.Effects.Count; index++) <button type="button" class="btn btn-link" @onclick="() => RemoveBaseEffect(index)">Remove</button>
{
var effect = Model.Effects[index];
<div class="critical-editor-card">
<div class="critical-editor-card-header">
<strong>Effect @(index + 1)</strong>
<button type="button" class="btn btn-link" @onclick="() => RemoveBaseEffect(index)">Remove</button>
</div>
@EffectFields(effect)
</div> </div>
} @EffectFields(effect)
</div>
} }
</section> }
</section>
<section class="critical-editor-section"> <section class="critical-editor-section">
<div class="critical-editor-section-header"> <div class="critical-editor-section-header">
<h4>Branches</h4> <h4>Branches</h4>
<button type="button" class="btn-ritual" @onclick="AddBranch">Add Branch</button> <button type="button" class="btn-ritual" @onclick="AddBranch">Add Branch</button>
</div> </div>
@if (Model.Branches.Count == 0) @if (Model.Branches.Count == 0)
{
<p class="muted">No branch records on this cell.</p>
}
else
{
@for (var index = 0; index < Model.Branches.Count; index++)
{ {
<p class="muted">No branch records on this cell.</p> var branch = Model.Branches[index];
} <div class="critical-editor-card branch-card-editor">
else <div class="critical-editor-card-header">
{ <strong>Branch @(index + 1)</strong>
@for (var index = 0; index < Model.Branches.Count; index++) <button type="button" class="btn btn-link" @onclick="() => RemoveBranch(index)">Remove</button>
{ </div>
var branch = Model.Branches[index]; <div class="form-grid">
<div class="critical-editor-card branch-card-editor"> <div class="field-shell">
<div class="critical-editor-card-header"> <label>Branch Kind</label>
<strong>Branch @(index + 1)</strong> <InputText class="input-shell" @bind-Value="branch.BranchKind" />
<button type="button" class="btn btn-link" @onclick="() => RemoveBranch(index)">Remove</button>
</div>
<div class="form-grid">
<div class="field-shell">
<label>Branch Kind</label>
<InputText class="input-shell" @bind-Value="branch.BranchKind" />
</div>
<div class="field-shell">
<label>Condition Key</label>
<InputText class="input-shell" @bind-Value="branch.ConditionKey" />
</div>
<div class="field-shell">
<label>Sort Order</label>
<InputNumber TValue="int" class="input-shell" @bind-Value="branch.SortOrder" />
</div>
</div> </div>
<div class="field-shell"> <div class="field-shell">
<label>Condition Text</label> <label>Condition Key</label>
<InputText class="input-shell" @bind-Value="branch.ConditionText" /> <InputText class="input-shell" @bind-Value="branch.ConditionKey" />
</div> </div>
<div class="field-shell"> <div class="field-shell">
<label>Raw Text</label> <label>Sort Order</label>
<InputTextArea class="input-shell critical-editor-textarea" @bind-Value="branch.RawText" /> <InputNumber TValue="int" class="input-shell" @bind-Value="branch.SortOrder" />
</div>
</div>
<div class="field-shell">
<label>Condition Text</label>
<InputText class="input-shell" @bind-Value="branch.ConditionText" />
</div>
<div class="field-shell">
<label>Raw Text</label>
<InputTextArea class="input-shell critical-editor-textarea" @bind-Value="branch.RawText" />
</div>
<div class="field-shell">
<label>Description / Prose</label>
<InputText class="input-shell" @bind-Value="branch.DescriptionText" />
</div>
<div class="field-shell">
<label>Affix Text</label>
<InputText class="input-shell" @bind-Value="branch.RawAffixText" />
</div>
<div class="form-grid">
<div class="field-shell">
<label>Condition Json</label>
<InputTextArea class="input-shell critical-editor-textarea compact" @bind-Value="branch.ConditionJson" />
</div> </div>
<div class="field-shell"> <div class="field-shell">
<label>Description / Prose</label> <label>Parsed Json</label>
<InputText class="input-shell" @bind-Value="branch.DescriptionText" /> <InputTextArea class="input-shell critical-editor-textarea json" @bind-Value="branch.ParsedJson" />
</div>
<div class="field-shell">
<label>Affix Text</label>
<InputText class="input-shell" @bind-Value="branch.RawAffixText" />
</div>
<div class="form-grid">
<div class="field-shell">
<label>Condition Json</label>
<InputTextArea class="input-shell critical-editor-textarea compact" @bind-Value="branch.ConditionJson" />
</div>
<div class="field-shell">
<label>Parsed Json</label>
<InputTextArea class="input-shell critical-editor-textarea json" @bind-Value="branch.ParsedJson" />
</div>
</div> </div>
</div>
<div class="critical-editor-subsection"> <div class="critical-editor-subsection">
<div class="critical-editor-section-header"> <div class="critical-editor-section-header">
<h5>Branch Effects</h5> <h5>Branch Effects</h5>
<button type="button" class="btn-ritual" @onclick="() => AddBranchEffect(branch)">Add Effect</button> <button type="button" class="btn-ritual" @onclick="() => AddBranchEffect(branch)">Add Effect</button>
</div> </div>
@if (branch.Effects.Count == 0) @if (branch.Effects.Count == 0)
{
<p class="muted">No normalized branch effects.</p>
}
else
{
@for (var effectIndex = 0; effectIndex < branch.Effects.Count; effectIndex++)
{ {
<p class="muted">No normalized branch effects.</p> var effect = branch.Effects[effectIndex];
} <div class="critical-editor-card nested">
else <div class="critical-editor-card-header">
{ <strong>Branch Effect @(effectIndex + 1)</strong>
@for (var effectIndex = 0; effectIndex < branch.Effects.Count; effectIndex++) <button type="button" class="btn btn-link" @onclick="() => RemoveBranchEffect(branch, effectIndex)">Remove</button>
{
var effect = branch.Effects[effectIndex];
<div class="critical-editor-card nested">
<div class="critical-editor-card-header">
<strong>Branch Effect @(effectIndex + 1)</strong>
<button type="button" class="btn btn-link" @onclick="() => RemoveBranchEffect(branch, effectIndex)">Remove</button>
</div>
@EffectFields(effect)
</div> </div>
} @EffectFields(effect)
</div>
} }
</div> }
</div> </div>
} </div>
} }
</section> }
</div> </section>
</div>
<footer class="critical-editor-footer"> <footer class="critical-editor-footer">
<button type="button" class="btn btn-link" @onclick="OnClose" disabled="@IsSaving">Cancel</button> <button type="button" class="btn btn-link" @onclick="OnClose" disabled="@IsSaving">Cancel</button>
<button type="submit" class="btn-ritual" disabled="@IsSaving"> <button type="submit" class="btn-ritual" disabled="@IsSaving">
@(IsSaving ? "Saving..." : "Save Cell") @(IsSaving ? "Saving..." : "Save Cell")
</button> </button>
</footer> </footer>
</EditForm> </EditForm>
} }
</div>
</div> </div>
} </div>
@code { @code {
[Parameter, EditorRequired] [Parameter, EditorRequired]
@@ -196,7 +206,10 @@
public bool IsSaving { get; set; } public bool IsSaving { get; set; }
[Parameter] [Parameter]
public string? ErrorMessage { get; set; } public string? LoadErrorMessage { get; set; }
[Parameter]
public string? SaveErrorMessage { get; set; }
[Parameter, EditorRequired] [Parameter, EditorRequired]
public EventCallback OnClose { get; set; } public EventCallback OnClose { get; set; }