feat(ui): tickets + plan day button, fallback list and prime action

This commit is contained in:
mika kuns
2026-10-01 08:44:21 +02:00
parent 9fc2e26edb
commit e35b054a2e
16 changed files with 242 additions and 12 deletions
@@ -58,4 +58,39 @@ public class PrepPanelViewModelTests
Assert.False(vm.PrepOperation.IsRunning);
Assert.True(vm.PlanDayCommand.CanExecute(null));
}
private sealed class TicketWorker : StubWorkerClient
{
public TicketSettingsDto? Settings { get; set; }
public override Task<TicketSettingsDto?> GetTicketSettingsAsync() => Task.FromResult(Settings);
}
[Theory]
[InlineData("http://api", true, true)]
[InlineData("http://api", false, false)]
[InlineData(null, true, false)]
public async Task TicketsConfigured_needs_base_url_and_token(string? url, bool tokenSet, bool expected)
{
var worker = new TicketWorker { Settings = new TicketSettingsDto(url, tokenSet) };
var vm = new PrepPanelViewModel(worker);
await vm.RefreshTicketsConfiguredAsync();
Assert.Equal(expected, vm.TicketsConfigured);
}
[Fact]
public async Task ImportTicketsAndPlanDay_calls_the_worker_and_shares_the_plan_day_lock()
{
var worker = new Worker();
var vm = new PrepPanelViewModel(worker);
var plan = vm.PlanDayCommand.ExecuteAsync(null);
Assert.False(vm.ImportTicketsAndPlanDayCommand.CanExecute(null));
worker.Gate.SetResult(true);
await plan;
await vm.ImportTicketsAndPlanDayCommand.ExecuteAsync(null);
Assert.Equal(1, worker.RunTicketImportNowCalls);
}
}
@@ -193,6 +193,19 @@ public class PrimeClaudeTabViewModelTests
Assert.False(vm.AnyFillMyDay);
}
[Fact]
public void Setting_IsImportTickets_Flips_Kind_And_Counts_As_FillMyDay()
{
var vm = new PrimeClaudeTabViewModel(new FakeApi());
vm.AddScheduleCommand.Execute(null);
vm.Rows[0].IsImportTickets = true;
Assert.Equal(PrimeActionKind.ImportTickets, vm.Rows[0].Kind);
Assert.False(vm.Rows[0].IsPing);
Assert.True(vm.AnyFillMyDay);
}
[Fact]
public async Task Save_Round_Trips_The_Kind()
{
@@ -0,0 +1,75 @@
using ClaudeDo.Data;
using ClaudeDo.Data.Models;
using ClaudeDo.Ui.ViewModels.Modals.Settings;
using Microsoft.EntityFrameworkCore;
using Xunit;
namespace ClaudeDo.Ui.Tests.ViewModels;
public sealed class TicketSettingsTabViewModelTests : IDisposable
{
private readonly string _dbPath = Path.Combine(Path.GetTempPath(), $"claudedo_ticketsettings_{Guid.NewGuid():N}.db");
public TicketSettingsTabViewModelTests()
{
using var ctx = NewContext();
ctx.Database.EnsureCreated();
ctx.Lists.Add(new ListEntity { Id = "l1", Name = "Hub", CreatedAt = DateTime.UtcNow, SortOrder = 0 });
ctx.Lists.Add(new ListEntity { Id = "l2", Name = "Inbox", CreatedAt = DateTime.UtcNow, SortOrder = 1 });
ctx.SaveChanges();
}
public void Dispose()
{
foreach (var suffix in new[] { "", "-wal", "-shm" })
try { File.Delete(_dbPath + suffix); } catch { }
}
private ClaudeDoDbContext NewContext() => new(new DbContextOptionsBuilder<ClaudeDoDbContext>()
.UseSqlite($"Data Source={_dbPath}").Options);
private sealed class Worker : StubWorkerClient
{
public TicketSettingsDto? Settings { get; set; }
public List<string?> SavedFallbacks { get; } = new();
public override Task<TicketSettingsDto?> GetTicketSettingsAsync() => Task.FromResult(Settings);
public override Task SetTicketFallbackListAsync(string? listId) { SavedFallbacks.Add(listId); return Task.CompletedTask; }
}
[Fact]
public async Task Load_offers_none_plus_every_list_and_selects_the_stored_fallback()
{
var worker = new Worker { Settings = new TicketSettingsDto("http://api", true, "l2") };
var vm = new TicketSettingsTabViewModel(worker, new TestDbFactory(NewContext));
await vm.LoadAsync();
Assert.Equal([null, "l1", "l2"], vm.FallbackLists.Select(o => o.Id));
Assert.Equal("l2", vm.SelectedFallbackList?.Id);
}
[Fact]
public async Task Save_writes_the_selected_fallback_and_none_as_null()
{
var worker = new Worker { Settings = new TicketSettingsDto("http://api", true, "l2") };
var vm = new TicketSettingsTabViewModel(worker, new TestDbFactory(NewContext));
await vm.LoadAsync();
vm.SelectedFallbackList = vm.FallbackLists[0];
await vm.SaveAsync();
Assert.Equal([null], worker.SavedFallbacks);
}
[Fact]
public async Task Save_does_not_touch_the_fallback_when_the_load_failed()
{
var worker = new Worker { Settings = null };
var vm = new TicketSettingsTabViewModel(worker, new TestDbFactory(NewContext));
await vm.LoadAsync();
await vm.SaveAsync();
Assert.Empty(worker.SavedFallbacks);
}
}