Gruppe 1 (Send to queue, Remove from queue, Cancel execution, Open quick session, Refine task) ist jetzt fix sichtbar und gated per IsEnabled + Grund statt komplett auszublenden. Planning/Schedule wandern in Untermenüs (Mark as existierte bereits); der Planning-Kopf zeigt einen Grund, wenn er sonst leer wäre. Refine-Button, ungesetzter Star und Dequeue-X erscheinen nur bei Hover-oder-Selektion (TaskRowViewModel.ShowRowActions); ein gesetzter Star und der Refining-Spinner bleiben immer sichtbar. Der Branch-Chip wandert aus der Zeile in eine Meta-Zeile in TaskHeaderBar. A3 headless verifiziert: Avalonia 12 zeigt ToolTips auf IsEnabled=false Controls nur mit ToolTip.ShowOnDisabled="True" (Default ist false) — dieses Attached Property existiert bereits und wird für die neuen Disabled-Reason- Tooltips genutzt.
163 lines
4.6 KiB
C#
163 lines
4.6 KiB
C#
using ClaudeDo.Data.Models;
|
|
using ClaudeDo.Ui.ViewModels.Islands;
|
|
using Xunit;
|
|
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
|
|
|
|
namespace ClaudeDo.Ui.Tests.ViewModels;
|
|
|
|
/// <summary>
|
|
/// [UX-Struktur A2/A4] Group 1's disabled-reason properties (grayed out with an explanation
|
|
/// instead of hidden — see task A1) and the hover-or-selected gate for the optional row actions.
|
|
/// </summary>
|
|
public class TaskRowContextMenuTests
|
|
{
|
|
private static TaskRowViewModel MakeRow() => new() { Id = "t1" };
|
|
|
|
[Fact]
|
|
public void SendToQueueDisabledReason_Null_When_Sendable()
|
|
{
|
|
var row = MakeRow();
|
|
row.Status = TaskStatus.Idle;
|
|
Assert.True(row.CanSendToQueue);
|
|
Assert.Null(row.SendToQueueDisabledReason);
|
|
}
|
|
|
|
[Fact]
|
|
public void SendToQueueDisabledReason_Set_When_AlreadyQueued()
|
|
{
|
|
var row = MakeRow();
|
|
row.Status = TaskStatus.Queued;
|
|
Assert.False(row.CanSendToQueue);
|
|
Assert.NotNull(row.SendToQueueDisabledReason);
|
|
}
|
|
|
|
[Fact]
|
|
public void SendToQueueDisabledReason_Set_When_Manual()
|
|
{
|
|
var row = MakeRow();
|
|
row.Status = TaskStatus.Idle;
|
|
row.IsManual = true;
|
|
Assert.False(row.CanSendToQueue);
|
|
Assert.NotNull(row.SendToQueueDisabledReason);
|
|
}
|
|
|
|
[Fact]
|
|
public void CancelDisabledReason_Null_While_Running()
|
|
{
|
|
var row = MakeRow();
|
|
row.Status = TaskStatus.Running;
|
|
Assert.Null(row.CancelDisabledReason);
|
|
}
|
|
|
|
[Fact]
|
|
public void CancelDisabledReason_Set_When_NotRunning()
|
|
{
|
|
var row = MakeRow();
|
|
row.Status = TaskStatus.Idle;
|
|
Assert.NotNull(row.CancelDisabledReason);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(TaskStatus.Idle)]
|
|
[InlineData(TaskStatus.Running)]
|
|
[InlineData(TaskStatus.Done)]
|
|
public void QuickSessionDisabledReason_Is_Always_Null(TaskStatus status)
|
|
{
|
|
var row = MakeRow();
|
|
row.Status = status;
|
|
row.IsManual = true;
|
|
Assert.Null(row.QuickSessionDisabledReason);
|
|
}
|
|
|
|
[Fact]
|
|
public void RefineDisabledReason_Null_When_Refinable()
|
|
{
|
|
var row = MakeRow();
|
|
row.Status = TaskStatus.Idle;
|
|
Assert.True(row.CanRefine);
|
|
Assert.Null(row.RefineDisabledReason);
|
|
}
|
|
|
|
[Fact]
|
|
public void RefineDisabledReason_Set_When_Manual()
|
|
{
|
|
var row = MakeRow();
|
|
row.Status = TaskStatus.Idle;
|
|
row.IsManual = true;
|
|
Assert.False(row.CanRefine);
|
|
Assert.NotNull(row.RefineDisabledReason);
|
|
}
|
|
|
|
[Fact]
|
|
public void RefineDisabledReason_Set_When_Refining()
|
|
{
|
|
var row = MakeRow();
|
|
row.Status = TaskStatus.Idle;
|
|
row.IsRefining = true;
|
|
Assert.False(row.CanRefine);
|
|
Assert.NotNull(row.RefineDisabledReason);
|
|
}
|
|
|
|
[Fact]
|
|
public void RefineDisabledReason_Set_When_NotIdle()
|
|
{
|
|
var row = MakeRow();
|
|
row.Status = TaskStatus.Running;
|
|
Assert.False(row.CanRefine);
|
|
Assert.NotNull(row.RefineDisabledReason);
|
|
}
|
|
|
|
[Fact]
|
|
public void PlanningDisabledReason_Null_When_OpenAvailable()
|
|
{
|
|
var row = MakeRow();
|
|
row.Status = TaskStatus.Idle;
|
|
Assert.True(row.CanOpenPlanningSession);
|
|
Assert.Null(row.PlanningDisabledReason);
|
|
}
|
|
|
|
[Fact]
|
|
public void PlanningDisabledReason_Null_When_PlanningActive()
|
|
{
|
|
var row = MakeRow();
|
|
row.Status = TaskStatus.Idle;
|
|
row.PlanningPhase = PlanningPhase.Active;
|
|
Assert.True(row.CanResumeOrDiscardPlanning);
|
|
Assert.Null(row.PlanningDisabledReason);
|
|
}
|
|
|
|
[Fact]
|
|
public void PlanningDisabledReason_Set_When_Finalized()
|
|
{
|
|
var row = MakeRow();
|
|
row.Status = TaskStatus.Idle;
|
|
row.PlanningPhase = PlanningPhase.Finalized;
|
|
Assert.False(row.CanOpenPlanningSession);
|
|
Assert.False(row.CanResumeOrDiscardPlanning);
|
|
Assert.False(row.CanFinalizePlanning);
|
|
Assert.NotNull(row.PlanningDisabledReason);
|
|
}
|
|
|
|
[Fact]
|
|
public void PlanningDisabledReason_Set_When_Manual()
|
|
{
|
|
var row = MakeRow();
|
|
row.Status = TaskStatus.Idle;
|
|
row.IsManual = true;
|
|
Assert.NotNull(row.PlanningDisabledReason);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(false, false, false)]
|
|
[InlineData(true, false, true)]
|
|
[InlineData(false, true, true)]
|
|
[InlineData(true, true, true)]
|
|
public void ShowRowActions_Follows_Hover_Or_Selection(bool isHovered, bool isSelected, bool expected)
|
|
{
|
|
var row = MakeRow();
|
|
row.IsHovered = isHovered;
|
|
row.IsSelected = isSelected;
|
|
Assert.Equal(expected, row.ShowRowActions);
|
|
}
|
|
}
|