Add manual critical table cell editor

This commit is contained in:
2026-03-14 15:09:16 +01:00
parent 4e518244a2
commit 6e28ad975f
16 changed files with 1105 additions and 27 deletions

View File

@@ -117,9 +117,26 @@
{
foreach (var column in detail.Columns)
{
<td>
@RenderCell(rollBand.Label, group.Key, column.Key)
</td>
@if (TryGetCell(rollBand.Label, group.Key, column.Key, out var groupedCell))
{
<td
class="critical-table-cell is-editable"
tabindex="0"
title="Click to edit this cell"
@onclick="() => OpenCellEditorAsync(groupedCell.ResultId)"
@onkeydown="args => HandleCellKeyDownAsync(args, groupedCell.ResultId)">
<CompactCriticalCell
Description="@(groupedCell.Description ?? string.Empty)"
Effects="@(groupedCell.Effects ?? Array.Empty<CriticalEffectLookupResponse>())"
Branches="@(groupedCell.Branches ?? Array.Empty<CriticalBranchLookupResponse>())" />
</td>
}
else
{
<td class="critical-table-cell">
<span class="empty-cell">—</span>
</td>
}
}
}
}
@@ -127,9 +144,26 @@
{
foreach (var column in detail.Columns)
{
<td>
@RenderCell(rollBand.Label, null, column.Key)
</td>
@if (TryGetCell(rollBand.Label, null, column.Key, out var cell))
{
<td
class="critical-table-cell is-editable"
tabindex="0"
title="Click to edit this cell"
@onclick="() => OpenCellEditorAsync(cell.ResultId)"
@onkeydown="args => HandleCellKeyDownAsync(args, cell.ResultId)">
<CompactCriticalCell
Description="@(cell.Description ?? string.Empty)"
Effects="@(cell.Effects ?? Array.Empty<CriticalEffectLookupResponse>())"
Branches="@(cell.Branches ?? Array.Empty<CriticalBranchLookupResponse>())" />
</td>
}
else
{
<td class="critical-table-cell">
<span class="empty-cell">—</span>
</td>
}
}
}
</tr>
@@ -164,6 +198,17 @@
}
</section>
@if (isEditorOpen)
{
<CriticalCellEditorDialog
Model="editorModel"
IsLoading="isEditorLoading"
IsSaving="isEditorSaving"
ErrorMessage="editorError"
OnClose="CloseCellEditorAsync"
OnSave="SaveCellEditorAsync" />
}
@code {
private LookupReferenceData? referenceData;
private CriticalTableDetail? tableDetail;
@@ -175,6 +220,12 @@
private int tableLayoutVersion;
private int appliedLayoutVersion = -1;
private bool IsTableSelectionDisabled => isReferenceDataLoading || (referenceData?.CriticalTables.Count ?? 0) == 0;
private bool isEditorOpen;
private bool isEditorLoading;
private bool isEditorSaving;
private string? editorError;
private int? editingResultId;
private CriticalCellEditorModel? editorModel;
protected override async Task OnInitializedAsync()
{
@@ -252,25 +303,6 @@
}
}
private RenderFragment RenderCell(string rollBand, string? groupKey, string columnKey) => builder =>
{
if (TryGetCell(rollBand, groupKey, columnKey, out var cell))
{
builder.OpenComponent(0, typeof(CompactCriticalCell));
builder.AddAttribute(1, "Description", cell.Description ?? string.Empty);
builder.AddAttribute(2, "Effects", cell.Effects ?? Array.Empty<CriticalEffectLookupResponse>());
builder.AddAttribute(3, "Branches", cell.Branches ?? Array.Empty<CriticalBranchLookupResponse>());
builder.CloseComponent();
}
else
{
builder.OpenElement(4, "span");
builder.AddAttribute(5, "class", "empty-cell");
builder.AddContent(6, "—");
builder.CloseElement();
}
};
private bool TryGetCell(string rollBand, string? groupKey, string columnKey, [NotNullWhen(true)] out CriticalTableCellDetail? cell)
{
if (cellIndex is null)
@@ -281,4 +313,91 @@
return cellIndex.TryGetValue((rollBand, groupKey, columnKey), out cell);
}
private async Task OpenCellEditorAsync(int resultId)
{
if (string.IsNullOrWhiteSpace(selectedTableSlug))
{
return;
}
isEditorOpen = true;
isEditorLoading = true;
isEditorSaving = false;
editorError = null;
editingResultId = resultId;
try
{
var response = await LookupService.GetCriticalCellEditorAsync(selectedTableSlug, resultId);
if (response is null)
{
editorError = "The selected cell could not be loaded for editing.";
editorModel = null;
return;
}
editorModel = CriticalCellEditorModel.FromResponse(response);
}
catch (Exception exception)
{
editorError = exception.Message;
editorModel = null;
}
finally
{
isEditorLoading = false;
}
}
private async Task CloseCellEditorAsync()
{
isEditorOpen = false;
isEditorLoading = false;
isEditorSaving = false;
editorError = null;
editingResultId = null;
editorModel = null;
await InvokeAsync(StateHasChanged);
}
private async Task SaveCellEditorAsync()
{
if (editorModel is null || string.IsNullOrWhiteSpace(selectedTableSlug) || editingResultId is null)
{
return;
}
isEditorSaving = true;
editorError = null;
try
{
var response = await LookupService.UpdateCriticalCellAsync(selectedTableSlug, editingResultId.Value, editorModel.ToRequest());
if (response is null)
{
editorError = "The selected cell could not be saved.";
return;
}
editorModel = CriticalCellEditorModel.FromResponse(response);
await LoadTableDetailAsync();
}
catch (Exception exception)
{
editorError = exception.Message;
}
finally
{
isEditorSaving = false;
}
}
private async Task HandleCellKeyDownAsync(KeyboardEventArgs args, int resultId)
{
if (args.Key is "Enter" or " ")
{
await OpenCellEditorAsync(resultId);
}
}
}