UX tweaks, traits bug fix, adding member info

This commit is contained in:
2026-04-16 11:50:11 -07:00
parent 7b624b3238
commit 8ff071c69b
43 changed files with 3248 additions and 3816 deletions

View File

@@ -0,0 +1,124 @@
using MicCheck.Api.Data;
using MicCheck.Api.Segments;
using Microsoft.EntityFrameworkCore;
namespace MicCheck.Api.Features;
public class FeatureSegmentService(MicCheckDbContext db)
{
public async Task<IReadOnlyList<FeatureSegmentResponse>> ListByFeatureAsync(
int featureId, int environmentId, CancellationToken ct = default)
{
var featureSegments = await db.FeatureSegments
.Where(fsg => fsg.FeatureId == featureId && fsg.EnvironmentId == environmentId)
.OrderBy(fsg => fsg.Priority)
.ToListAsync(ct);
var segmentIds = featureSegments.Select(fsg => fsg.SegmentId).Distinct().ToList();
var segments = await db.Segments
.Where(s => segmentIds.Contains(s.Id))
.ToDictionaryAsync(s => s.Id, ct);
var states = await db.FeatureStates
.Where(fs => fs.FeatureId == featureId && fs.EnvironmentId == environmentId && fs.FeatureSegmentId != null)
.ToListAsync(ct);
var stateBySegment = states.ToDictionary(fs => fs.FeatureSegmentId!.Value);
return featureSegments.Select(fsg =>
{
var segmentName = segments.TryGetValue(fsg.SegmentId, out var seg) ? seg.Name : "Unknown";
stateBySegment.TryGetValue(fsg.Id, out var state);
return new FeatureSegmentResponse(
fsg.Id, fsg.FeatureId, fsg.SegmentId, segmentName,
fsg.EnvironmentId, fsg.Priority,
state?.Enabled, state?.Value);
}).ToList();
}
public async Task<FeatureSegmentResponse> CreateAsync(
int featureId, int environmentId, int segmentId, int priority, bool enabled, string? value,
CancellationToken ct = default)
{
var segment = await db.Segments.FirstOrDefaultAsync(s => s.Id == segmentId, ct)
?? throw new KeyNotFoundException($"Segment {segmentId} not found.");
var featureSegment = new FeatureSegment
{
FeatureId = featureId,
SegmentId = segmentId,
EnvironmentId = environmentId,
Priority = priority
};
db.FeatureSegments.Add(featureSegment);
await db.SaveChangesAsync(ct);
var state = new FeatureState
{
FeatureId = featureId,
EnvironmentId = environmentId,
FeatureSegmentId = featureSegment.Id,
Enabled = enabled,
Value = value,
CreatedAt = DateTimeOffset.UtcNow,
UpdatedAt = DateTimeOffset.UtcNow
};
db.FeatureStates.Add(state);
await db.SaveChangesAsync(ct);
return new FeatureSegmentResponse(
featureSegment.Id, featureId, segmentId, segment.Name,
environmentId, priority, enabled, value);
}
public async Task<FeatureSegmentResponse?> UpdateAsync(
int id, int priority, bool enabled, string? value, CancellationToken ct = default)
{
var featureSegment = await db.FeatureSegments.FirstOrDefaultAsync(fsg => fsg.Id == id, ct);
if (featureSegment is null) return null;
var segment = await db.Segments.FirstOrDefaultAsync(s => s.Id == featureSegment.SegmentId, ct);
featureSegment.Priority = priority;
var state = await db.FeatureStates
.FirstOrDefaultAsync(fs => fs.FeatureSegmentId == id, ct);
if (state is not null)
{
state.Enabled = enabled;
state.Value = value;
state.UpdatedAt = DateTimeOffset.UtcNow;
}
else
{
state = new FeatureState
{
FeatureId = featureSegment.FeatureId,
EnvironmentId = featureSegment.EnvironmentId,
FeatureSegmentId = featureSegment.Id,
Enabled = enabled,
Value = value,
CreatedAt = DateTimeOffset.UtcNow,
UpdatedAt = DateTimeOffset.UtcNow
};
db.FeatureStates.Add(state);
}
await db.SaveChangesAsync(ct);
return new FeatureSegmentResponse(
featureSegment.Id, featureSegment.FeatureId, featureSegment.SegmentId,
segment?.Name ?? "Unknown", featureSegment.EnvironmentId,
priority, enabled, value);
}
public async Task<bool> DeleteAsync(int id, CancellationToken ct = default)
{
var featureSegment = await db.FeatureSegments.FirstOrDefaultAsync(fsg => fsg.Id == id, ct);
if (featureSegment is null) return false;
db.FeatureSegments.Remove(featureSegment);
await db.SaveChangesAsync(ct);
return true;
}
}