feat(ui): tickets + plan day button, fallback list and prime action
This commit is contained in:
@@ -169,6 +169,8 @@ public abstract class StubWorkerClient : IWorkerClient
|
||||
public virtual Task<string?> GetWeekReportAsync(DateOnly start, DateOnly end) => Task.FromResult<string?>(null);
|
||||
public virtual Task<string> GenerateWeekReportAsync(DateOnly start, DateOnly end) => Task.FromResult("");
|
||||
public virtual Task<bool> RunDailyPrepNowAsync() { RunDailyPrepNowCalls++; return Task.FromResult(false); }
|
||||
public int RunTicketImportNowCalls { get; private set; }
|
||||
public virtual Task<bool> RunTicketImportNowAsync() { RunTicketImportNowCalls++; return Task.FromResult(false); }
|
||||
public virtual Task ClearMyDayAsync() { ClearMyDayCalls++; return Task.CompletedTask; }
|
||||
public virtual Task<AppSettingsDto?> GetAppSettingsAsync() => Task.FromResult<AppSettingsDto?>(null);
|
||||
public virtual Task UpdateAppSettingsAsync(AppSettingsDto dto) => Task.CompletedTask;
|
||||
@@ -220,6 +222,7 @@ public abstract class StubWorkerClient : IWorkerClient
|
||||
Task.FromResult<TokenTrackerDashboardDto?>(new TokenTrackerDashboardDto(true, "http://127.0.0.1:7681/", null));
|
||||
|
||||
public virtual Task<TicketSettingsDto?> GetTicketSettingsAsync() => Task.FromResult<TicketSettingsDto?>(null);
|
||||
public virtual Task SetTicketFallbackListAsync(string? listId) => Task.CompletedTask;
|
||||
public virtual Task SetTicketApiBaseUrlAsync(string? baseUrl) => Task.CompletedTask;
|
||||
public virtual Task SetTicketTokenAsync(string token) => Task.CompletedTask;
|
||||
public virtual Task ClearTicketTokenAsync() => Task.CompletedTask;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user