fix(tickets): Import broadcastet TaskUpdated fuer neue Tasks
ImportTickets sendete nur ListUpdated. Die UI liest das als Aenderung der Listen-Metadaten und patcht nur bestehende Zeilen, also tauchten die importierten Tasks erst nach Schliessen und Neuoeffnen der Liste auf. TicketImportResult liefert jetzt die angelegten Task-Ids, der Hub broadcastet pro Id ein TaskUpdated - derselbe Pfad, den jeder andere out-of-band Creator nutzt.
This commit is contained in:
@@ -1394,6 +1394,11 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await _ticketImport.ImportAsync(listId, Context.ConnectionAborted);
|
var result = await _ticketImport.ImportAsync(listId, Context.ConnectionAborted);
|
||||||
|
// ListUpdated allein reicht nicht: die UI liest das als "Listen-Metadaten geaendert"
|
||||||
|
// und patcht nur bestehende Zeilen. Neue Tasks tauchen nur ueber TaskUpdated auf, wie
|
||||||
|
// bei jedem anderen out-of-band Creator (add_task und Co.).
|
||||||
|
foreach (var taskId in result.CreatedTaskIds)
|
||||||
|
await _broadcaster.TaskUpdated(taskId);
|
||||||
await _broadcaster.ListUpdated(listId);
|
await _broadcaster.ListUpdated(listId);
|
||||||
return new TicketImportResultDto(result.Examined, result.Created);
|
return new TicketImportResultDto(result.Examined, result.Created);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
|
|||||||
|
|
||||||
namespace ClaudeDo.Worker.Tickets;
|
namespace ClaudeDo.Worker.Tickets;
|
||||||
|
|
||||||
public sealed record TicketImportResult(int Examined, int Created);
|
public sealed record TicketImportResult(int Examined, int Created, IReadOnlyList<string> CreatedTaskIds);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Holt das Board des verknüpften Ticket-Projekts und legt für jedes offene, dem Token-Inhaber
|
/// Holt das Board des verknüpften Ticket-Projekts und legt für jedes offene, dem Token-Inhaber
|
||||||
@@ -61,16 +61,17 @@ public sealed class TicketImportService
|
|||||||
var knownSet = known.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
var knownSet = known.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
var repo = new TaskRepository(ctx);
|
var repo = new TaskRepository(ctx);
|
||||||
var created = 0;
|
var created = new List<string>();
|
||||||
|
|
||||||
foreach (var ticket in mine)
|
foreach (var ticket in mine)
|
||||||
{
|
{
|
||||||
var reference = $"bandel:{ticket.Id}";
|
var reference = $"bandel:{ticket.Id}";
|
||||||
if (!knownSet.Add(reference)) continue;
|
if (!knownSet.Add(reference)) continue;
|
||||||
|
|
||||||
|
var taskId = Guid.NewGuid().ToString();
|
||||||
await repo.AddAsync(new TaskEntity
|
await repo.AddAsync(new TaskEntity
|
||||||
{
|
{
|
||||||
Id = Guid.NewGuid().ToString(),
|
Id = taskId,
|
||||||
ListId = listId,
|
ListId = listId,
|
||||||
Title = ticket.Title,
|
Title = ticket.Title,
|
||||||
Description = BuildDescription(ticket),
|
Description = BuildDescription(ticket),
|
||||||
@@ -79,14 +80,14 @@ public sealed class TicketImportService
|
|||||||
TicketRef = reference,
|
TicketRef = reference,
|
||||||
CreatedBy = "ticketsystem",
|
CreatedBy = "ticketsystem",
|
||||||
}, ct);
|
}, ct);
|
||||||
created++;
|
created.Add(taskId);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation(
|
_logger.LogInformation(
|
||||||
"Ticket-Import für Liste {list_id}: {examined} geprüft, {created} neue Tasks",
|
"Ticket-Import für Liste {list_id}: {examined} geprüft, {created} neue Tasks",
|
||||||
listId, board.Count, created);
|
listId, board.Count, created.Count);
|
||||||
|
|
||||||
return new TicketImportResult(board.Count, created);
|
return new TicketImportResult(board.Count, created.Count, created);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -43,6 +43,14 @@ public sealed class TicketImportServiceTests : IDisposable
|
|||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
Assert.Equal(["bandel:1", "bandel:3"], refs.Order());
|
Assert.Equal(["bandel:1", "bandel:3"], refs.Order());
|
||||||
|
|
||||||
|
// Ohne die Ids kann der Hub kein TaskUpdated broadcasten und die offene Liste
|
||||||
|
// zeigt die neuen Tasks erst nach Schließen/Öffnen.
|
||||||
|
var createdIds = await ctx.Tasks
|
||||||
|
.Where(t => t.CreatedBy == "ticketsystem")
|
||||||
|
.Select(t => t.Id)
|
||||||
|
.ToListAsync();
|
||||||
|
Assert.Equal(createdIds.Order(), result.CreatedTaskIds.Order());
|
||||||
|
|
||||||
var created = await ctx.Tasks.Where(t => t.TicketRef == "bandel:1").SingleAsync();
|
var created = await ctx.Tasks.Where(t => t.TicketRef == "bandel:1").SingleAsync();
|
||||||
Assert.Equal("Fix X", created.Title);
|
Assert.Equal("Fix X", created.Title);
|
||||||
Assert.Equal(TaskStatus.Idle, created.Status);
|
Assert.Equal(TaskStatus.Idle, created.Status);
|
||||||
|
|||||||
Reference in New Issue
Block a user