Track critical curation summaries and edit resets
This commit is contained in:
@@ -34,6 +34,9 @@ public sealed record CriticalTableReference(
|
||||
string Family,
|
||||
string SourceDocument,
|
||||
string? Notes,
|
||||
int CuratedResultCount,
|
||||
int TotalResultCount,
|
||||
int CurationPercentage,
|
||||
IReadOnlyList<CriticalColumnReference> Columns,
|
||||
IReadOnlyList<CriticalGroupReference> Groups,
|
||||
IReadOnlyList<CriticalRollBandReference> RollBands);
|
||||
|
||||
@@ -43,6 +43,20 @@ public sealed class LookupService(
|
||||
.OrderBy(item => item.DisplayName)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var criticalResultCounts = await dbContext.CriticalResults
|
||||
.AsNoTracking()
|
||||
.GroupBy(item => item.CriticalTableId)
|
||||
.Select(group => new
|
||||
{
|
||||
CriticalTableId = group.Key,
|
||||
TotalCount = group.Count(),
|
||||
CuratedCount = group.Count(item => item.IsCurated)
|
||||
})
|
||||
.ToDictionaryAsync(
|
||||
item => item.CriticalTableId,
|
||||
item => (item.CuratedCount, item.TotalCount),
|
||||
cancellationToken);
|
||||
|
||||
return new LookupReferenceData(
|
||||
attackTables,
|
||||
armorTypes,
|
||||
@@ -52,6 +66,9 @@ public sealed class LookupService(
|
||||
item.Family,
|
||||
item.SourceDocument,
|
||||
item.Notes,
|
||||
GetCuratedCount(item.Id),
|
||||
GetTotalCount(item.Id),
|
||||
GetCurationPercentage(item.Id),
|
||||
item.Columns
|
||||
.OrderBy(column => column.SortOrder)
|
||||
.Select(column => new CriticalColumnReference(column.ColumnKey, column.Label, column.Role, column.SortOrder))
|
||||
@@ -65,6 +82,22 @@ public sealed class LookupService(
|
||||
.Select(rollBand => new CriticalRollBandReference(rollBand.Label, rollBand.MinRoll, rollBand.MaxRoll, rollBand.SortOrder))
|
||||
.ToList()))
|
||||
.ToList());
|
||||
|
||||
int GetCuratedCount(int tableId) =>
|
||||
criticalResultCounts.TryGetValue(tableId, out var counts) ? counts.CuratedCount : 0;
|
||||
|
||||
int GetTotalCount(int tableId) =>
|
||||
criticalResultCounts.TryGetValue(tableId, out var counts) ? counts.TotalCount : 0;
|
||||
|
||||
int GetCurationPercentage(int tableId)
|
||||
{
|
||||
if (!criticalResultCounts.TryGetValue(tableId, out var counts) || counts.TotalCount == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int)Math.Round((double)counts.CuratedCount * 100 / counts.TotalCount, MidpointRounding.AwayFromZero);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<AttackLookupResponse?> LookupAttackAsync(AttackLookupRequest request, CancellationToken cancellationToken = default)
|
||||
@@ -383,12 +416,15 @@ public sealed class LookupService(
|
||||
return null;
|
||||
}
|
||||
|
||||
var currentState = CreateCurrentEditorState(result);
|
||||
var hasEdits = HasCriticalCellEdits(currentState, request);
|
||||
|
||||
result.RawCellText = request.RawCellText.Trim();
|
||||
result.DescriptionText = request.DescriptionText.Trim();
|
||||
result.RawAffixText = NormalizeOptionalText(request.RawAffixText);
|
||||
result.ParseStatus = request.ParseStatus.Trim();
|
||||
result.ParsedJson = CriticalCellEditorSnapshot.FromRequest(request).ToJson();
|
||||
result.IsCurated = request.IsCurated;
|
||||
result.IsCurated = hasEdits ? false : request.IsCurated;
|
||||
|
||||
ReplaceBaseEffects(dbContext, result, request.Effects);
|
||||
ReplaceBranches(dbContext, result, request.Branches);
|
||||
@@ -396,7 +432,11 @@ public sealed class LookupService(
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
var generatedContent = await ParseCriticalCellContentAsync(dbContext, result.CriticalTableId, request.QuickParseInput, cancellationToken);
|
||||
return CreateCellEditorResponse(result, request, generatedContent.ValidationErrors, CreateComparisonState(generatedContent));
|
||||
var persistedState = request with
|
||||
{
|
||||
IsCurated = result.IsCurated
|
||||
};
|
||||
return CreateCellEditorResponse(result, persistedState, generatedContent.ValidationErrors, CreateComparisonState(generatedContent));
|
||||
}
|
||||
|
||||
private static IReadOnlyList<CriticalTableLegendEntry> BuildLegend(IReadOnlyList<CriticalTableCellDetail> cells)
|
||||
@@ -1023,6 +1063,96 @@ public sealed class LookupService(
|
||||
private static string? NormalizeOptionalText(string? value) =>
|
||||
string.IsNullOrWhiteSpace(value) ? null : value.Trim();
|
||||
|
||||
private static bool HasCriticalCellEdits(CriticalCellUpdateRequest currentState, CriticalCellUpdateRequest request)
|
||||
{
|
||||
if (!string.Equals(currentState.RawCellText.Trim(), request.RawCellText.Trim(), StringComparison.Ordinal) ||
|
||||
!string.Equals(currentState.QuickParseInput.Trim(), request.QuickParseInput.Trim(), StringComparison.Ordinal) ||
|
||||
!string.Equals(currentState.DescriptionText.Trim(), request.DescriptionText.Trim(), StringComparison.Ordinal) ||
|
||||
!string.Equals(NormalizeOptionalText(currentState.RawAffixText), NormalizeOptionalText(request.RawAffixText), StringComparison.Ordinal) ||
|
||||
!string.Equals(currentState.ParseStatus.Trim(), request.ParseStatus.Trim(), StringComparison.Ordinal) ||
|
||||
currentState.IsDescriptionOverridden != request.IsDescriptionOverridden ||
|
||||
currentState.IsRawAffixTextOverridden != request.IsRawAffixTextOverridden ||
|
||||
currentState.AreEffectsOverridden != request.AreEffectsOverridden ||
|
||||
currentState.AreBranchesOverridden != request.AreBranchesOverridden)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return !EffectListsEqual(currentState.Effects, request.Effects) ||
|
||||
!BranchListsEqual(currentState.Branches, request.Branches);
|
||||
}
|
||||
|
||||
private static bool EffectListsEqual(
|
||||
IReadOnlyList<CriticalEffectEditorItem> left,
|
||||
IReadOnlyList<CriticalEffectEditorItem> right)
|
||||
{
|
||||
if (left.Count != right.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var index = 0; index < left.Count; index++)
|
||||
{
|
||||
if (!EffectsEqual(left[index], right[index]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool BranchListsEqual(
|
||||
IReadOnlyList<CriticalBranchEditorItem> left,
|
||||
IReadOnlyList<CriticalBranchEditorItem> right)
|
||||
{
|
||||
if (left.Count != right.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var index = 0; index < left.Count; index++)
|
||||
{
|
||||
if (!BranchesEqual(left[index], right[index]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool EffectsEqual(CriticalEffectEditorItem left, CriticalEffectEditorItem right) =>
|
||||
string.Equals(left.EffectCode.Trim(), right.EffectCode.Trim(), StringComparison.Ordinal) &&
|
||||
string.Equals(NormalizeOptionalText(left.Target), NormalizeOptionalText(right.Target), StringComparison.Ordinal) &&
|
||||
left.ValueInteger == right.ValueInteger &&
|
||||
left.ValueDecimal == right.ValueDecimal &&
|
||||
string.Equals(NormalizeOptionalText(left.ValueExpression), NormalizeOptionalText(right.ValueExpression), StringComparison.Ordinal) &&
|
||||
left.DurationRounds == right.DurationRounds &&
|
||||
left.PerRound == right.PerRound &&
|
||||
left.Modifier == right.Modifier &&
|
||||
string.Equals(NormalizeOptionalText(left.BodyPart), NormalizeOptionalText(right.BodyPart), StringComparison.Ordinal) &&
|
||||
left.IsPermanent == right.IsPermanent &&
|
||||
string.Equals(left.SourceType.Trim(), right.SourceType.Trim(), StringComparison.Ordinal) &&
|
||||
string.Equals(NormalizeOptionalText(left.SourceText), NormalizeOptionalText(right.SourceText), StringComparison.Ordinal) &&
|
||||
string.Equals(NormalizeOptionalText(left.OriginKey), NormalizeOptionalText(right.OriginKey), StringComparison.Ordinal) &&
|
||||
left.IsOverridden == right.IsOverridden;
|
||||
|
||||
private static bool BranchesEqual(CriticalBranchEditorItem left, CriticalBranchEditorItem right) =>
|
||||
string.Equals(left.BranchKind.Trim(), right.BranchKind.Trim(), StringComparison.Ordinal) &&
|
||||
string.Equals(NormalizeOptionalText(left.ConditionKey), NormalizeOptionalText(right.ConditionKey), StringComparison.Ordinal) &&
|
||||
string.Equals(left.ConditionText.Trim(), right.ConditionText.Trim(), StringComparison.Ordinal) &&
|
||||
string.Equals(left.ConditionJson.Trim(), right.ConditionJson.Trim(), StringComparison.Ordinal) &&
|
||||
string.Equals(left.RawText.Trim(), right.RawText.Trim(), StringComparison.Ordinal) &&
|
||||
string.Equals(left.DescriptionText.Trim(), right.DescriptionText.Trim(), StringComparison.Ordinal) &&
|
||||
string.Equals(NormalizeOptionalText(left.RawAffixText), NormalizeOptionalText(right.RawAffixText), StringComparison.Ordinal) &&
|
||||
string.Equals(left.ParsedJson.Trim(), right.ParsedJson.Trim(), StringComparison.Ordinal) &&
|
||||
left.SortOrder == right.SortOrder &&
|
||||
string.Equals(NormalizeOptionalText(left.OriginKey), NormalizeOptionalText(right.OriginKey), StringComparison.Ordinal) &&
|
||||
left.IsOverridden == right.IsOverridden &&
|
||||
left.AreEffectsOverridden == right.AreEffectsOverridden &&
|
||||
EffectListsEqual(left.Effects, right.Effects);
|
||||
|
||||
private static string NormalizeSlug(string value) =>
|
||||
value.Trim().Replace(' ', '_').ToLowerInvariant();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user