refactor: extract interfaces to Interfaces folders and consolidate filters

Move interface declarations into per-area Interfaces/ subfolders, merge the
small task-list filter classes into StatusFilter/SmartFlagFilter, and simplify
related services, converters and hub DTO handling.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-05-30 15:41:10 +02:00
parent 77100b6b3b
commit 41da124a31
42 changed files with 306 additions and 532 deletions

View File

@@ -41,6 +41,27 @@ public sealed class TaskMergeService
_logger = logger;
}
private async Task<(TaskEntity Task, ListEntity List, WorktreeEntity? Worktree)> LoadMergeContextAsync(
string taskId, CancellationToken ct)
{
using var ctx = _dbFactory.CreateDbContext();
var task = await new TaskRepository(ctx).GetByIdAsync(taskId, ct)
?? throw new KeyNotFoundException($"Task '{taskId}' not found.");
var list = await new ListRepository(ctx).GetByIdAsync(task.ListId, ct)
?? throw new InvalidOperationException("List not found.");
var wt = await new WorktreeRepository(ctx).GetByTaskIdAsync(taskId, ct);
return (task, list, wt);
}
private async Task MarkWorktreeMergedAsync(string taskId, CancellationToken ct)
{
using (var ctx = _dbFactory.CreateDbContext())
{
await new WorktreeRepository(ctx).SetStateAsync(taskId, WorktreeState.Merged, ct);
}
await _broadcaster.WorktreeUpdated(taskId);
}
public async Task<MergeResult> MergeAsync(
string taskId,
string targetBranch,
@@ -49,18 +70,7 @@ public sealed class TaskMergeService
bool leaveConflictsInTree,
CancellationToken ct)
{
TaskEntity task;
ListEntity list;
WorktreeEntity? wt;
using (var ctx = _dbFactory.CreateDbContext())
{
task = await new TaskRepository(ctx).GetByIdAsync(taskId, ct)
?? throw new KeyNotFoundException($"Task '{taskId}' not found.");
list = await new ListRepository(ctx).GetByIdAsync(task.ListId, ct)
?? throw new InvalidOperationException("List not found.");
wt = await new WorktreeRepository(ctx).GetByTaskIdAsync(taskId, ct);
}
var (task, list, wt) = await LoadMergeContextAsync(taskId, ct);
if (task.Status == TaskStatus.Running)
return Blocked("task is running");
@@ -134,11 +144,7 @@ public sealed class TaskMergeService
}
}
using (var ctx = _dbFactory.CreateDbContext())
{
await new WorktreeRepository(ctx).SetStateAsync(taskId, WorktreeState.Merged, ct);
}
await _broadcaster.WorktreeUpdated(taskId);
await MarkWorktreeMergedAsync(taskId, ct);
_logger.LogInformation(
"Merged task {TaskId} branch {Branch} into {Target} (remove worktree: {Remove})",
@@ -158,18 +164,7 @@ public sealed class TaskMergeService
public async Task<MergeResult> ContinueMergeAsync(string taskId, CancellationToken ct)
{
TaskEntity task;
ListEntity list;
WorktreeEntity? wt;
using (var ctx = _dbFactory.CreateDbContext())
{
task = await new TaskRepository(ctx).GetByIdAsync(taskId, ct)
?? throw new KeyNotFoundException($"Task '{taskId}' not found.");
list = await new ListRepository(ctx).GetByIdAsync(task.ListId, ct)
?? throw new InvalidOperationException("List not found.");
wt = await new WorktreeRepository(ctx).GetByTaskIdAsync(taskId, ct);
}
var (_, list, wt) = await LoadMergeContextAsync(taskId, ct);
if (wt is null) return Blocked("task has no worktree");
if (wt.State != WorktreeState.Active) return Blocked($"worktree state is {wt.State}");
@@ -186,11 +181,7 @@ public sealed class TaskMergeService
try { await _git.CommitAsync(list.WorkingDir, $"Merge branch '{wt.BranchName}'", ct); }
catch (Exception ex) { return Blocked($"commit failed: {ex.Message}"); }
using (var ctx = _dbFactory.CreateDbContext())
{
await new WorktreeRepository(ctx).SetStateAsync(taskId, WorktreeState.Merged, ct);
}
await _broadcaster.WorktreeUpdated(taskId);
await MarkWorktreeMergedAsync(taskId, ct);
_logger.LogInformation("Continued merge of task {TaskId} branch {Branch}", taskId, wt.BranchName);
return new MergeResult(StatusMerged, Array.Empty<string>(), null);
@@ -198,17 +189,7 @@ public sealed class TaskMergeService
public async Task<MergeResult> AbortMergeAsync(string taskId, CancellationToken ct)
{
ListEntity list;
WorktreeEntity? wt;
using (var ctx = _dbFactory.CreateDbContext())
{
var task = await new TaskRepository(ctx).GetByIdAsync(taskId, ct)
?? throw new KeyNotFoundException($"Task '{taskId}' not found.");
list = await new ListRepository(ctx).GetByIdAsync(task.ListId, ct)
?? throw new InvalidOperationException("List not found.");
wt = await new WorktreeRepository(ctx).GetByTaskIdAsync(taskId, ct);
}
var (_, list, wt) = await LoadMergeContextAsync(taskId, ct);
if (wt is null) return Blocked("task has no worktree");
if (wt.State != WorktreeState.Active) return Blocked($"worktree state is {wt.State}");
@@ -225,15 +206,7 @@ public sealed class TaskMergeService
public async Task<MergeTargets> GetTargetsAsync(string taskId, CancellationToken ct)
{
TaskEntity task;
ListEntity list;
using (var ctx = _dbFactory.CreateDbContext())
{
task = await new TaskRepository(ctx).GetByIdAsync(taskId, ct)
?? throw new KeyNotFoundException($"Task '{taskId}' not found.");
list = await new ListRepository(ctx).GetByIdAsync(task.ListId, ct)
?? throw new InvalidOperationException("List not found.");
}
var (_, list, _) = await LoadMergeContextAsync(taskId, ct);
if (string.IsNullOrWhiteSpace(list.WorkingDir))
return new MergeTargets("", Array.Empty<string>());