feat: planning sessions foundation (Plan A) #4
@@ -346,6 +346,37 @@ public sealed class TaskRepository
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<bool> DiscardPlanningAsync(
|
||||||
|
string parentId,
|
||||||
|
CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
using var tx = await _context.Database.BeginTransactionAsync(ct);
|
||||||
|
|
||||||
|
var parent = await _context.Tasks
|
||||||
|
.AsNoTracking()
|
||||||
|
.FirstOrDefaultAsync(t => t.Id == parentId, ct);
|
||||||
|
if (parent is null || parent.Status != TaskStatus.Planning)
|
||||||
|
{
|
||||||
|
await tx.RollbackAsync(ct);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _context.Tasks
|
||||||
|
.Where(t => t.ParentTaskId == parentId && t.Status == TaskStatus.Draft)
|
||||||
|
.ExecuteDeleteAsync(ct);
|
||||||
|
|
||||||
|
await _context.Tasks
|
||||||
|
.Where(t => t.Id == parentId)
|
||||||
|
.ExecuteUpdateAsync(s => s
|
||||||
|
.SetProperty(t => t.Status, TaskStatus.Manual)
|
||||||
|
.SetProperty(t => t.PlanningSessionId, (string?)null)
|
||||||
|
.SetProperty(t => t.PlanningSessionToken, (string?)null)
|
||||||
|
.SetProperty(t => t.PlanningFinalizedAt, (DateTime?)null), ct);
|
||||||
|
|
||||||
|
await tx.CommitAsync(ct);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Queue selection
|
#region Queue selection
|
||||||
|
|||||||
@@ -246,4 +246,40 @@ public sealed class TaskRepositoryPlanningTests : IDisposable
|
|||||||
var cLoaded = await _tasks.GetByIdAsync(c.Id);
|
var cLoaded = await _tasks.GetByIdAsync(c.Id);
|
||||||
Assert.Equal(TaskStatus.Queued, cLoaded!.Status);
|
Assert.Equal(TaskStatus.Queued, cLoaded!.Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task DiscardPlanningAsync_DeletesDraftsAndResetsParent()
|
||||||
|
{
|
||||||
|
var listId = await CreateListAsync();
|
||||||
|
var parent = MakeTask(listId, TaskStatus.Manual);
|
||||||
|
await _tasks.AddAsync(parent);
|
||||||
|
await _tasks.SetPlanningStartedAsync(parent.Id, "tok");
|
||||||
|
await _tasks.UpdatePlanningSessionIdAsync(parent.Id, "claude-42");
|
||||||
|
var c1 = await _tasks.CreateChildAsync(parent.Id, "c1", null, null, null);
|
||||||
|
var c2 = await _tasks.CreateChildAsync(parent.Id, "c2", null, null, null);
|
||||||
|
|
||||||
|
var ok = await _tasks.DiscardPlanningAsync(parent.Id);
|
||||||
|
|
||||||
|
Assert.True(ok);
|
||||||
|
Assert.Null(await _tasks.GetByIdAsync(c1.Id));
|
||||||
|
Assert.Null(await _tasks.GetByIdAsync(c2.Id));
|
||||||
|
|
||||||
|
var parentLoaded = await _tasks.GetByIdAsync(parent.Id);
|
||||||
|
Assert.Equal(TaskStatus.Manual, parentLoaded!.Status);
|
||||||
|
Assert.Null(parentLoaded.PlanningSessionId);
|
||||||
|
Assert.Null(parentLoaded.PlanningSessionToken);
|
||||||
|
Assert.Null(parentLoaded.PlanningFinalizedAt);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task DiscardPlanningAsync_OnNonPlanningTask_ReturnsFalse()
|
||||||
|
{
|
||||||
|
var listId = await CreateListAsync();
|
||||||
|
var task = MakeTask(listId, TaskStatus.Manual);
|
||||||
|
await _tasks.AddAsync(task);
|
||||||
|
|
||||||
|
var ok = await _tasks.DiscardPlanningAsync(task.Id);
|
||||||
|
|
||||||
|
Assert.False(ok);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user