fix(mission-control): show post-merge verify as Verifying instead of In review
Derived from the VerifyMerge entry in RunningOperations (no new TaskStatus). The Running now row stays, reworded to 'Verifying after merge'. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
5dae5ff679
commit
46e9303da6
@@ -384,7 +384,7 @@
|
|||||||
"settings": "Einstellungen",
|
"settings": "Einstellungen",
|
||||||
"activity": "Aktivität",
|
"activity": "Aktivität",
|
||||||
"runningNow": "Läuft gerade",
|
"runningNow": "Läuft gerade",
|
||||||
"opVerifyMerge": "Verify (Merge)",
|
"opVerifyMerge": "Prüfung nach Merge",
|
||||||
"opVerifyBatch": "Verify (Batch)",
|
"opVerifyBatch": "Verify (Batch)",
|
||||||
"opMerging": "Merge",
|
"opMerging": "Merge",
|
||||||
"opRebasing": "Rebase",
|
"opRebasing": "Rebase",
|
||||||
@@ -393,6 +393,7 @@
|
|||||||
"blocked": "Blockiert",
|
"blocked": "Blockiert",
|
||||||
"running": "Läuft",
|
"running": "Läuft",
|
||||||
"review": "Im Review",
|
"review": "Im Review",
|
||||||
|
"verifying": "Wird geprüft",
|
||||||
"failed": "Fehlgeschlagen",
|
"failed": "Fehlgeschlagen",
|
||||||
"roadblock": "Blockade gemeldet",
|
"roadblock": "Blockade gemeldet",
|
||||||
"openSession": "Sitzung öffnen",
|
"openSession": "Sitzung öffnen",
|
||||||
|
|||||||
@@ -384,7 +384,7 @@
|
|||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
"activity": "Activity",
|
"activity": "Activity",
|
||||||
"runningNow": "Running now",
|
"runningNow": "Running now",
|
||||||
"opVerifyMerge": "Verify (merge)",
|
"opVerifyMerge": "Verifying after merge",
|
||||||
"opVerifyBatch": "Verify (batch)",
|
"opVerifyBatch": "Verify (batch)",
|
||||||
"opMerging": "Merging",
|
"opMerging": "Merging",
|
||||||
"opRebasing": "Rebasing",
|
"opRebasing": "Rebasing",
|
||||||
@@ -393,6 +393,7 @@
|
|||||||
"blocked": "Blocked",
|
"blocked": "Blocked",
|
||||||
"running": "Running",
|
"running": "Running",
|
||||||
"review": "In review",
|
"review": "In review",
|
||||||
|
"verifying": "Verifying",
|
||||||
"failed": "Failed",
|
"failed": "Failed",
|
||||||
"roadblock": "Roadblock reported",
|
"roadblock": "Roadblock reported",
|
||||||
"openSession": "Open session",
|
"openSession": "Open session",
|
||||||
|
|||||||
@@ -157,10 +157,12 @@ public sealed partial class MissionControlViewModel : ViewModelBase, IDisposable
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var snapshot = await _worker.GetActiveOperationsAsync();
|
var snapshot = await _worker.GetActiveOperationsAsync();
|
||||||
|
var hadVerify = RunningOperations.Any(IsVerifyMerge);
|
||||||
RunningOperations.Clear();
|
RunningOperations.Clear();
|
||||||
foreach (var op in snapshot.Where(o => !_endedOperationIds.Contains(o.Id)).OrderBy(o => o.StartedAt))
|
foreach (var op in snapshot.Where(o => !_endedOperationIds.Contains(o.Id)).OrderBy(o => o.StartedAt))
|
||||||
RunningOperations.Add(new RunningOperationViewModel(op));
|
RunningOperations.Add(new RunningOperationViewModel(op));
|
||||||
NotifyOperationsChanged();
|
NotifyOperationsChanged();
|
||||||
|
if (hadVerify || RunningOperations.Any(IsVerifyMerge)) _ = RefreshQueueAsync();
|
||||||
}
|
}
|
||||||
catch (Exception ex) { ErrorReported?.Invoke(Loc.T("missionControl.operationsRefreshFailed", ex.Message)); }
|
catch (Exception ex) { ErrorReported?.Invoke(Loc.T("missionControl.operationsRefreshFailed", ex.Message)); }
|
||||||
}
|
}
|
||||||
@@ -171,8 +173,10 @@ public sealed partial class MissionControlViewModel : ViewModelBase, IDisposable
|
|||||||
private void AddOperation(RunningOperationDto op)
|
private void AddOperation(RunningOperationDto op)
|
||||||
{
|
{
|
||||||
if (_endedOperationIds.Contains(op.Id) || RunningOperations.Any(r => r.Id == op.Id)) return;
|
if (_endedOperationIds.Contains(op.Id) || RunningOperations.Any(r => r.Id == op.Id)) return;
|
||||||
RunningOperations.Add(new RunningOperationViewModel(op));
|
var row = new RunningOperationViewModel(op);
|
||||||
|
RunningOperations.Add(row);
|
||||||
NotifyOperationsChanged();
|
NotifyOperationsChanged();
|
||||||
|
if (IsVerifyMerge(row)) _ = RefreshQueueAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveOperation(string id)
|
private void RemoveOperation(string id)
|
||||||
@@ -182,8 +186,12 @@ public sealed partial class MissionControlViewModel : ViewModelBase, IDisposable
|
|||||||
if (row is null) return;
|
if (row is null) return;
|
||||||
RunningOperations.Remove(row);
|
RunningOperations.Remove(row);
|
||||||
NotifyOperationsChanged();
|
NotifyOperationsChanged();
|
||||||
|
if (IsVerifyMerge(row)) _ = RefreshQueueAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>A post-merge verify keeps its task in WaitingForReview, so only this op marks the activity row "Verifying".</summary>
|
||||||
|
private static bool IsVerifyMerge(RunningOperationViewModel r) => r.Kind == OperationKinds.VerifyMerge;
|
||||||
|
|
||||||
private void NotifyOperationsChanged()
|
private void NotifyOperationsChanged()
|
||||||
{
|
{
|
||||||
OnPropertyChanged(nameof(HasRunningOperations));
|
OnPropertyChanged(nameof(HasRunningOperations));
|
||||||
@@ -220,7 +228,8 @@ public sealed partial class MissionControlViewModel : ViewModelBase, IDisposable
|
|||||||
{
|
{
|
||||||
var id = r.Id;
|
var id = r.Id;
|
||||||
var running = r.Status == ClaudeDo.Data.Models.TaskStatus.Running;
|
var running = r.Status == ClaudeDo.Data.Models.TaskStatus.Running;
|
||||||
var (tint, colorKey, labelKey) = Decorate(r.Status, r.RoadblockCount, r.BlockedByTaskId != null);
|
var (tint, colorKey, labelKey) = Decorate(r.Status, r.RoadblockCount, r.BlockedByTaskId != null,
|
||||||
|
RunningOperations.Any(o => o.Kind == OperationKinds.VerifyMerge && o.TaskId == id));
|
||||||
Queued.Add(new QueuedTaskViewModel
|
Queued.Add(new QueuedTaskViewModel
|
||||||
{
|
{
|
||||||
Id = id,
|
Id = id,
|
||||||
@@ -243,12 +252,14 @@ public sealed partial class MissionControlViewModel : ViewModelBase, IDisposable
|
|||||||
// Row tint + status label for the activity strip. Keys are resolved to brushes by
|
// Row tint + status label for the activity strip. Keys are resolved to brushes by
|
||||||
// DotBrushConverter ("<key>Brush"), so they must match tokens in Tokens.axaml.
|
// DotBrushConverter ("<key>Brush"), so they must match tokens in Tokens.axaml.
|
||||||
private static (string? Tint, string? ColorKey, string? LabelKey) Decorate(
|
private static (string? Tint, string? ColorKey, string? LabelKey) Decorate(
|
||||||
ClaudeDo.Data.Models.TaskStatus status, int roadblockCount, bool blocked)
|
ClaudeDo.Data.Models.TaskStatus status, int roadblockCount, bool blocked, bool verifying)
|
||||||
=> status switch
|
=> status switch
|
||||||
{
|
{
|
||||||
ClaudeDo.Data.Models.TaskStatus.Failed => ("ErrorTint", "StatusError", "missionControl.failed"),
|
ClaudeDo.Data.Models.TaskStatus.Failed => ("ErrorTint", "StatusError", "missionControl.failed"),
|
||||||
ClaudeDo.Data.Models.TaskStatus.WaitingForReview when roadblockCount > 0
|
ClaudeDo.Data.Models.TaskStatus.WaitingForReview when roadblockCount > 0
|
||||||
=> ("RoadblockTint", "Amber", "missionControl.roadblock"),
|
=> ("RoadblockTint", "Amber", "missionControl.roadblock"),
|
||||||
|
ClaudeDo.Data.Models.TaskStatus.WaitingForReview when verifying
|
||||||
|
=> ("RunningTint", "StatusRunning", "missionControl.verifying"),
|
||||||
ClaudeDo.Data.Models.TaskStatus.WaitingForReview => ("DoneTint", "StatusReview", "missionControl.review"),
|
ClaudeDo.Data.Models.TaskStatus.WaitingForReview => ("DoneTint", "StatusReview", "missionControl.review"),
|
||||||
ClaudeDo.Data.Models.TaskStatus.Running => ("RunningTint", "StatusRunning", "missionControl.running"),
|
ClaudeDo.Data.Models.TaskStatus.Running => ("RunningTint", "StatusRunning", "missionControl.running"),
|
||||||
_ when blocked => (null, "Amber", "missionControl.blocked"),
|
_ when blocked => (null, "Amber", "missionControl.blocked"),
|
||||||
@@ -890,7 +901,11 @@ public sealed partial class RunningOperationViewModel : ObservableObject
|
|||||||
private readonly DateTime _startedAtUtc;
|
private readonly DateTime _startedAtUtc;
|
||||||
|
|
||||||
public string Id { get; }
|
public string Id { get; }
|
||||||
/// <summary>Localized operation kind ("Verify (merge)", "Rebasing", ...).</summary>
|
/// <summary>Wire kind token (<see cref="OperationKinds"/>).</summary>
|
||||||
|
public string Kind { get; }
|
||||||
|
/// <summary>The task the operation runs for; null for a batch verify.</summary>
|
||||||
|
public string? TaskId { get; }
|
||||||
|
/// <summary>Localized operation kind ("Verifying after merge", "Rebasing", ...).</summary>
|
||||||
public string KindLabel { get; }
|
public string KindLabel { get; }
|
||||||
/// <summary><c>#Number Title</c> for a task operation, the list name for a batch verify.</summary>
|
/// <summary><c>#Number Title</c> for a task operation, the list name for a batch verify.</summary>
|
||||||
public string Subject { get; }
|
public string Subject { get; }
|
||||||
@@ -900,6 +915,8 @@ public sealed partial class RunningOperationViewModel : ObservableObject
|
|||||||
public RunningOperationViewModel(RunningOperationDto op)
|
public RunningOperationViewModel(RunningOperationDto op)
|
||||||
{
|
{
|
||||||
Id = op.Id;
|
Id = op.Id;
|
||||||
|
Kind = op.Kind;
|
||||||
|
TaskId = op.TaskId;
|
||||||
_startedAtUtc = op.StartedAt;
|
_startedAtUtc = op.StartedAt;
|
||||||
KindLabel = op.Kind switch
|
KindLabel = op.Kind switch
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using ClaudeDo.Data;
|
using ClaudeDo.Data;
|
||||||
|
using ClaudeDo.Data.Models;
|
||||||
|
using ClaudeDo.Ui.Localization;
|
||||||
using ClaudeDo.Ui.Services;
|
using ClaudeDo.Ui.Services;
|
||||||
using ClaudeDo.Ui.ViewModels;
|
using ClaudeDo.Ui.ViewModels;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@@ -126,6 +128,30 @@ public class MissionControlRunningOperationsTests : IDisposable
|
|||||||
Assert.Equal("c", Assert.Single(vm.RunningOperations).Id);
|
Assert.Equal("c", Assert.Single(vm.RunningOperations).Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task VerifyMergeOperation_ShowsReviewTaskAsVerifying_UntilItEnds()
|
||||||
|
{
|
||||||
|
await using (var db = NewContext())
|
||||||
|
{
|
||||||
|
db.Lists.Add(new ListEntity { Id = "L1", Name = "Work", CreatedAt = DateTime.UtcNow });
|
||||||
|
db.Tasks.Add(new TaskEntity { Number = TestTaskNumbers.Next(), Id = "rev1", ListId = "L1", Title = "review", Status = ClaudeDo.Data.Models.TaskStatus.WaitingForReview, CreatedAt = DateTime.UtcNow });
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
var worker = new FakeWorker();
|
||||||
|
using var vm = BuildVm(worker);
|
||||||
|
await vm.RefreshQueueAsync();
|
||||||
|
Assert.Equal(Loc.T("missionControl.review"), vm.Queued.Single().StatusLabel);
|
||||||
|
|
||||||
|
worker.RaiseOperationStarted(new RunningOperationDto("v1", OperationKinds.VerifyMerge, "rev1", 1, "L1", "review", DateTime.UtcNow));
|
||||||
|
await vm.RefreshQueueAsync();
|
||||||
|
Assert.Equal(Loc.T("missionControl.verifying"), vm.Queued.Single().StatusLabel);
|
||||||
|
Assert.Equal("StatusRunning", vm.Queued.Single().StatusColorKey);
|
||||||
|
|
||||||
|
worker.RaiseOperationEnded("v1");
|
||||||
|
await vm.RefreshQueueAsync();
|
||||||
|
Assert.Equal(Loc.T("missionControl.review"), vm.Queued.Single().StatusLabel);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task TickOperations_UpdatesElapsed()
|
public async Task TickOperations_UpdatesElapsed()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user