feat(notes): notes get their own list, a day log and an Enter chain
The editor was reachable from one button that only appeared in My Day, which is how it got forgotten. It is now a permanent sidebar entry next to My Day and Planned, and it fills the tasks island rather than the details pane, because a note list is content. Inside, the date picker is gone: today sits at the top with the capture box, older days follow as dated groups. Enter in a note saves it and opens the next one, Shift+Enter breaks the line so notes can be several, Backspace on an empty note deletes it and steps back up. Deleting also has a visible hover button instead of only "clear the text and hope". Agent-written notes carry a marker. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ae0c7d3771
commit
0f04b796f4
@@ -48,7 +48,7 @@ public class DetailsIslandConflictSeamTests : IDisposable
|
||||
private DetailsIslandViewModel BuildVm(StubWorkerClient worker, MergeCoordinator merge)
|
||||
{
|
||||
var factory = new TestDbFactory(NewContext);
|
||||
return new DetailsIslandViewModel(factory, worker, new NullServiceProvider(), new StubNotesApi(), merge);
|
||||
return new DetailsIslandViewModel(factory, worker, new NullServiceProvider(), merge);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -56,7 +56,7 @@ public class DetailsIslandDeleteTaskTests : IDisposable
|
||||
private DetailsIslandViewModel BuildVm(RecordingWorkerClient worker)
|
||||
{
|
||||
var factory = new TestDbFactory(NewContext);
|
||||
return new DetailsIslandViewModel(factory, worker, new NullServiceProvider(), new StubNotesApi(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
return new DetailsIslandViewModel(factory, worker, new NullServiceProvider(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -59,7 +59,7 @@ public class DetailsIslandDescriptionSaveRaceTests : IDisposable
|
||||
}
|
||||
|
||||
private DetailsIslandViewModel BuildVm() =>
|
||||
new(new TestDbFactory(NewContext), new FakeWorker(), new NullServiceProvider(), new StubNotesApi(),
|
||||
new(new TestDbFactory(NewContext), new FakeWorker(), new NullServiceProvider(),
|
||||
new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
|
||||
private async Task<TaskEntity> ReadTaskAsync(string id)
|
||||
|
||||
@@ -38,7 +38,7 @@ public class DetailsIslandEmptyStateTests : IDisposable
|
||||
private DetailsIslandViewModel NewDetailsVm(StubWorkerClient stub)
|
||||
{
|
||||
var factory = new TestDbFactory(NewContext);
|
||||
return new DetailsIslandViewModel(factory, stub, new NullServiceProvider(), new StubNotesApi(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
return new DetailsIslandViewModel(factory, stub, new NullServiceProvider(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -60,17 +60,6 @@ public class DetailsIslandEmptyStateTests : IDisposable
|
||||
Assert.False(vm.IsEmptyStateVisible);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsEmptyStateVisible_false_in_notes_mode_even_without_a_task()
|
||||
{
|
||||
var vm = NewDetailsVm(new DefaultStub());
|
||||
|
||||
vm.ShowNotes();
|
||||
|
||||
Assert.True(vm.IsNotesMode);
|
||||
Assert.Null(vm.Task);
|
||||
Assert.False(vm.IsEmptyStateVisible);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsEmptyStateVisible_false_in_prep_mode_even_without_a_task()
|
||||
|
||||
@@ -86,7 +86,7 @@ public class DetailsIslandErrorFeedbackTests : IDisposable
|
||||
{
|
||||
var factory = new TestDbFactory(NewContext);
|
||||
return new DetailsIslandViewModel(
|
||||
factory, worker, new NullServiceProvider(), new StubNotesApi(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
factory, worker, new NullServiceProvider(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -48,7 +48,7 @@ public class DetailsIslandHandlerRangeTests : IDisposable
|
||||
{
|
||||
var factory = new TestDbFactory(NewContext);
|
||||
return new DetailsIslandViewModel(
|
||||
factory, new FakeWorkerClient(), new NullServiceProvider(), new StubNotesApi(), new MergeCoordinator());
|
||||
factory, new FakeWorkerClient(), new NullServiceProvider(), new MergeCoordinator());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -47,7 +47,7 @@ public class DetailsIslandPlanningTests : IDisposable
|
||||
private DetailsIslandViewModel BuildVm(StubWorkerClient worker)
|
||||
{
|
||||
var factory = new TestDbFactory(NewContext);
|
||||
return new DetailsIslandViewModel(factory, worker, new NullServiceProvider(), new StubNotesApi(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
return new DetailsIslandViewModel(factory, worker, new NullServiceProvider(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
}
|
||||
|
||||
// Connected worker whose review calls fail the way the hub does when the task
|
||||
|
||||
@@ -37,7 +37,7 @@ public class DetailsIslandPrepModeTests : IDisposable
|
||||
private DetailsIslandViewModel NewDetailsVm(StubWorkerClient stub)
|
||||
{
|
||||
var factory = new TestDbFactory(NewContext);
|
||||
return new DetailsIslandViewModel(factory, stub, new NullServiceProvider(), new StubNotesApi(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
return new DetailsIslandViewModel(factory, stub, new NullServiceProvider(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
}
|
||||
|
||||
|
||||
@@ -53,13 +53,12 @@ public class DetailsIslandPrepModeTests : IDisposable
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShowPrep_sets_prep_mode_and_clears_notes_mode()
|
||||
public void ShowPrep_sets_prep_mode_and_hides_the_task_detail()
|
||||
{
|
||||
var vm = NewDetailsVm(new DefaultStub());
|
||||
vm.ShowPrep();
|
||||
|
||||
Assert.True(vm.IsPrepMode);
|
||||
Assert.False(vm.IsNotesMode);
|
||||
Assert.False(vm.IsTaskDetailVisible);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public class DetailsIslandResetAndRetryTests : IDisposable
|
||||
{
|
||||
var factory = new TestDbFactory(NewContext);
|
||||
return new DetailsIslandViewModel(
|
||||
factory, worker, new NullServiceProvider(), new StubNotesApi(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
factory, worker, new NullServiceProvider(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -50,7 +50,7 @@ public class DetailsIslandReviewActionsTests : IDisposable
|
||||
private DetailsIslandViewModel BuildVm(StubWorkerClient worker)
|
||||
{
|
||||
var factory = new TestDbFactory(NewContext);
|
||||
return new DetailsIslandViewModel(factory, worker, new NullServiceProvider(), new StubNotesApi(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
return new DetailsIslandViewModel(factory, worker, new NullServiceProvider(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -63,7 +63,7 @@ public class DetailsIslandRoadblockReplyTests : IDisposable
|
||||
private DetailsIslandViewModel BuildVm(StubWorkerClient worker)
|
||||
{
|
||||
var factory = new TestDbFactory(NewContext);
|
||||
return new DetailsIslandViewModel(factory, worker, new NullServiceProvider(), new StubNotesApi(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
return new DetailsIslandViewModel(factory, worker, new NullServiceProvider(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
}
|
||||
|
||||
private static DetailsIslandViewModel PrepareDoneTaskWithRoadblock(DetailsIslandViewModel vm, string taskId = "task-rb-1")
|
||||
|
||||
@@ -38,7 +38,7 @@ public class DetailsIslandTabsTests : IDisposable
|
||||
private DetailsIslandViewModel NewVm()
|
||||
{
|
||||
var factory = new TestDbFactory(NewContext);
|
||||
return new DetailsIslandViewModel(factory, new DefaultStub(), new NullServiceProvider(), new StubNotesApi(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
return new DetailsIslandViewModel(factory, new DefaultStub(), new NullServiceProvider(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -40,7 +40,7 @@ public class DetailsIslandTaskIdBadgeTests : IDisposable
|
||||
private DetailsIslandViewModel NewVm()
|
||||
{
|
||||
var factory = new TestDbFactory(NewContext);
|
||||
return new DetailsIslandViewModel(factory, new DefaultStub(), new NullServiceProvider(), new StubNotesApi(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
return new DetailsIslandViewModel(factory, new DefaultStub(), new NullServiceProvider(), new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -57,7 +57,7 @@ public class DetailsIslandTaskUpdatedTests : IDisposable
|
||||
}
|
||||
|
||||
private DetailsIslandViewModel BuildVm(StubWorkerClient worker) =>
|
||||
new(new TestDbFactory(NewContext), worker, new NullServiceProvider(), new StubNotesApi(),
|
||||
new(new TestDbFactory(NewContext), worker, new NullServiceProvider(),
|
||||
new ClaudeDo.Ui.Services.MergeCoordinator());
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -6,42 +6,110 @@ namespace ClaudeDo.Ui.Tests.ViewModels;
|
||||
|
||||
public class NotesEditorViewModelTests
|
||||
{
|
||||
private static readonly DateOnly Today = DateOnly.FromDateTime(DateTime.Today);
|
||||
|
||||
private sealed class FakeNotes : INotesApi
|
||||
{
|
||||
public readonly List<DailyNoteDto> Store = new();
|
||||
private int _seq;
|
||||
|
||||
public Task<List<DailyNoteDto>> ListAsync(DateOnly day) =>
|
||||
Task.FromResult(Store.Where(n => n.Date == day.ToString("yyyy-MM-dd")).ToList());
|
||||
Task.FromResult(Store.Where(n => n.Date == Iso(day)).ToList());
|
||||
|
||||
public Task<List<DailyNoteDto>> ListBetweenAsync(DateOnly start, DateOnly end) =>
|
||||
Task.FromResult(Store
|
||||
.Where(n => DateOnly.Parse(n.Date) >= start && DateOnly.Parse(n.Date) <= end)
|
||||
.ToList());
|
||||
|
||||
public Task<DailyNoteDto?> AddAsync(DateOnly day, string text)
|
||||
{
|
||||
var dto = new DailyNoteDto($"id{_seq++}", day.ToString("yyyy-MM-dd"), text, Store.Count);
|
||||
var dto = new DailyNoteDto($"id{_seq++}", Iso(day), text, Store.Count, false);
|
||||
Store.Add(dto);
|
||||
return Task.FromResult<DailyNoteDto?>(dto);
|
||||
}
|
||||
|
||||
public Task UpdateAsync(string id, string text)
|
||||
{
|
||||
var i = Store.FindIndex(n => n.Id == id);
|
||||
if (i >= 0) Store[i] = Store[i] with { Text = text };
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task DeleteAsync(string id) { Store.RemoveAll(n => n.Id == id); return Task.CompletedTask; }
|
||||
|
||||
public void Seed(DateOnly day, string text, bool fromAgent = false) =>
|
||||
Store.Add(new DailyNoteDto($"id{_seq++}", Iso(day), text, Store.Count, fromAgent));
|
||||
|
||||
private static string Iso(DateOnly d) => d.ToString("yyyy-MM-dd");
|
||||
}
|
||||
|
||||
private sealed class ThrowingNotes : INotesApi
|
||||
{
|
||||
public string ExceptionMessage { get; init; } = "worker offline";
|
||||
public Task<List<DailyNoteDto>> ListAsync(DateOnly day) => Task.FromResult(new List<DailyNoteDto>());
|
||||
public Task<List<DailyNoteDto>> ListBetweenAsync(DateOnly start, DateOnly end) => Task.FromResult(new List<DailyNoteDto>());
|
||||
public Task<DailyNoteDto?> AddAsync(DateOnly day, string text) => throw new Exception(ExceptionMessage);
|
||||
public Task UpdateAsync(string id, string text) => Task.CompletedTask;
|
||||
public Task DeleteAsync(string id) => Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static async Task<(NotesEditorViewModel vm, FakeNotes api)> LoadedAsync(Action<FakeNotes>? seed = null)
|
||||
{
|
||||
var api = new FakeNotes();
|
||||
seed?.Invoke(api);
|
||||
var vm = new NotesEditorViewModel(api);
|
||||
await vm.LoadAsync();
|
||||
return (vm, api);
|
||||
}
|
||||
|
||||
private static List<NoteBulletViewModel> Bullets(NotesEditorViewModel vm) =>
|
||||
vm.Rows.OfType<NoteBulletViewModel>().ToList();
|
||||
|
||||
[Fact]
|
||||
public async Task LoadAsync_groups_notes_by_day_with_today_first()
|
||||
{
|
||||
var (vm, _) = await LoadedAsync(api =>
|
||||
{
|
||||
api.Seed(Today.AddDays(-2), "vorgestern");
|
||||
api.Seed(Today, "heute");
|
||||
});
|
||||
|
||||
var headers = vm.Rows.OfType<NoteDayHeaderViewModel>().ToList();
|
||||
Assert.Equal(Today, headers[0].Day);
|
||||
Assert.True(headers[0].IsToday);
|
||||
Assert.Equal(Today.AddDays(-2), headers[1].Day);
|
||||
Assert.Equal("heute", ((NoteBulletViewModel)vm.Rows[1]).Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LoadAsync_keeps_todays_header_when_there_is_nothing_yet()
|
||||
{
|
||||
var (vm, _) = await LoadedAsync();
|
||||
|
||||
Assert.Single(vm.Rows);
|
||||
Assert.True(vm.IsEmpty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddBullet_files_the_note_under_today_and_clears_the_box()
|
||||
{
|
||||
var (vm, api) = await LoadedAsync(api => api.Seed(Today.AddDays(-1), "gestern"));
|
||||
|
||||
vm.NewBulletText = "Standup vorbereitet";
|
||||
await vm.AddBulletCommand.ExecuteAsync(null);
|
||||
|
||||
Assert.Equal("Standup vorbereitet", ((NoteBulletViewModel)vm.Rows[1]).Text);
|
||||
Assert.Equal("", vm.NewBulletText);
|
||||
Assert.False(vm.IsEmpty);
|
||||
Assert.Equal(2, api.Store.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddBullet_WhenApiThrows_RaisesErrorReported_AndKeepsDraftText()
|
||||
{
|
||||
var api = new ThrowingNotes();
|
||||
var vm = new NotesEditorViewModel(api);
|
||||
await vm.LoadDayAsync(new DateOnly(2026, 6, 1));
|
||||
await vm.LoadAsync();
|
||||
|
||||
string? reportedError = null;
|
||||
vm.ErrorReported += msg => reportedError = msg;
|
||||
@@ -50,73 +118,123 @@ public class NotesEditorViewModelTests
|
||||
await vm.AddBulletCommand.ExecuteAsync(null);
|
||||
|
||||
Assert.Equal(api.ExceptionMessage, reportedError);
|
||||
Assert.Empty(vm.Bullets);
|
||||
Assert.Empty(Bullets(vm));
|
||||
Assert.Equal("Standup vorbereitet", vm.NewBulletText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddBullet_PersistsAndAppears_ForCurrentDay()
|
||||
public async Task SplitBullet_saves_the_edit_then_opens_an_empty_row_below_and_focuses_it()
|
||||
{
|
||||
var api = new FakeNotes();
|
||||
var vm = new NotesEditorViewModel(api);
|
||||
await vm.LoadDayAsync(new DateOnly(2026, 6, 1));
|
||||
var (vm, api) = await LoadedAsync(api => api.Seed(Today, "erste"));
|
||||
NoteBulletViewModel? focused = null;
|
||||
vm.FocusRequested += b => focused = b;
|
||||
|
||||
vm.NewBulletText = "Standup vorbereitet";
|
||||
await vm.AddBulletCommand.ExecuteAsync(null);
|
||||
var first = Bullets(vm)[0];
|
||||
first.Text = "erste, bearbeitet";
|
||||
await vm.SplitBulletCommand.ExecuteAsync(first);
|
||||
|
||||
Assert.Single(vm.Bullets);
|
||||
Assert.Equal("Standup vorbereitet", vm.Bullets[0].Text);
|
||||
Assert.Equal("", vm.NewBulletText);
|
||||
var rows = Bullets(vm);
|
||||
Assert.Equal(2, rows.Count);
|
||||
Assert.Same(rows[1], focused);
|
||||
Assert.True(rows[1].IsNew);
|
||||
Assert.Equal("erste, bearbeitet", api.Store[0].Text);
|
||||
// The empty row is UI-only until it gets text, so Enter on a blank line leaves nothing behind.
|
||||
Assert.Single(api.Store);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PrevAndNextDay_NavigateAndReload()
|
||||
public async Task SplitBullet_on_an_emptied_note_deletes_it_and_adds_no_row()
|
||||
{
|
||||
var api = new FakeNotes();
|
||||
await api.AddAsync(new DateOnly(2026, 5, 31), "gestern");
|
||||
var vm = new NotesEditorViewModel(api);
|
||||
await vm.LoadDayAsync(new DateOnly(2026, 6, 1));
|
||||
Assert.Empty(vm.Bullets);
|
||||
var (vm, api) = await LoadedAsync(api => api.Seed(Today, "weg damit"));
|
||||
|
||||
await vm.PrevDayCommand.ExecuteAsync(null);
|
||||
Assert.Equal(new DateOnly(2026, 5, 31), vm.CurrentDay);
|
||||
Assert.Single(vm.Bullets);
|
||||
var only = Bullets(vm)[0];
|
||||
only.Text = " ";
|
||||
await vm.SplitBulletCommand.ExecuteAsync(only);
|
||||
|
||||
await vm.NextDayCommand.ExecuteAsync(null);
|
||||
Assert.Equal(new DateOnly(2026, 6, 1), vm.CurrentDay);
|
||||
Assert.Empty(vm.Bullets);
|
||||
Assert.Empty(Bullets(vm));
|
||||
Assert.Empty(api.Store);
|
||||
Assert.True(vm.IsEmpty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CommitBullet_persists_a_new_row_and_gives_it_an_id()
|
||||
{
|
||||
var (vm, api) = await LoadedAsync(api => api.Seed(Today, "erste"));
|
||||
await vm.SplitBulletCommand.ExecuteAsync(Bullets(vm)[0]);
|
||||
|
||||
var fresh = Bullets(vm)[1];
|
||||
fresh.Text = "zweite";
|
||||
await vm.CommitBulletCommand.ExecuteAsync(fresh);
|
||||
|
||||
Assert.False(fresh.IsNew);
|
||||
Assert.Equal(2, api.Store.Count);
|
||||
Assert.Equal("zweite", api.Store[1].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteBullet_removes_it_and_focuses_the_note_above()
|
||||
{
|
||||
var (vm, api) = await LoadedAsync(api => { api.Seed(Today, "eins"); api.Seed(Today, "zwei"); });
|
||||
NoteBulletViewModel? focused = null;
|
||||
vm.FocusRequested += b => focused = b;
|
||||
|
||||
var second = Bullets(vm)[1];
|
||||
await vm.DeleteBulletCommand.ExecuteAsync(second);
|
||||
|
||||
Assert.Single(Bullets(vm));
|
||||
Assert.Equal("eins", focused?.Text);
|
||||
Assert.Single(api.Store);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteBullet_on_the_first_note_of_the_day_does_not_reach_into_the_header()
|
||||
{
|
||||
var (vm, _) = await LoadedAsync(api => api.Seed(Today, "einzige"));
|
||||
var focusCalls = 0;
|
||||
vm.FocusRequested += _ => focusCalls++;
|
||||
|
||||
await vm.DeleteBulletCommand.ExecuteAsync(Bullets(vm)[0]);
|
||||
|
||||
Assert.Equal(0, focusCalls);
|
||||
Assert.True(vm.IsEmpty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CommitBullet_EmptyText_RemovesFromStoreAndList()
|
||||
{
|
||||
var api = new FakeNotes();
|
||||
var vm = new NotesEditorViewModel(api);
|
||||
await vm.LoadDayAsync(new DateOnly(2026, 6, 1));
|
||||
vm.NewBulletText = "weg damit";
|
||||
await vm.AddBulletCommand.ExecuteAsync(null);
|
||||
var (vm, api) = await LoadedAsync(api => api.Seed(Today, "weg damit"));
|
||||
|
||||
vm.Bullets[0].Text = " ";
|
||||
await vm.CommitBulletCommand.ExecuteAsync(vm.Bullets[0]);
|
||||
var only = Bullets(vm)[0];
|
||||
only.Text = " ";
|
||||
await vm.CommitBulletCommand.ExecuteAsync(only);
|
||||
|
||||
Assert.Empty(vm.Bullets);
|
||||
Assert.Empty(Bullets(vm));
|
||||
Assert.Empty(api.Store);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CommitBullet_NonEmptyText_PersistsEdit()
|
||||
{
|
||||
var api = new FakeNotes();
|
||||
var vm = new NotesEditorViewModel(api);
|
||||
await vm.LoadDayAsync(new DateOnly(2026, 6, 1));
|
||||
vm.NewBulletText = "original";
|
||||
await vm.AddBulletCommand.ExecuteAsync(null);
|
||||
var (vm, api) = await LoadedAsync(api => api.Seed(Today, "original"));
|
||||
|
||||
vm.Bullets[0].Text = "geändert";
|
||||
await vm.CommitBulletCommand.ExecuteAsync(vm.Bullets[0]);
|
||||
var only = Bullets(vm)[0];
|
||||
only.Text = "geaendert";
|
||||
await vm.CommitBulletCommand.ExecuteAsync(only);
|
||||
|
||||
Assert.Single(vm.Bullets);
|
||||
Assert.Equal("geändert", api.Store[0].Text);
|
||||
Assert.Single(Bullets(vm));
|
||||
Assert.Equal("geaendert", api.Store[0].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Agent_written_notes_are_marked_so_the_view_can_flag_them()
|
||||
{
|
||||
var (vm, _) = await LoadedAsync(api =>
|
||||
{
|
||||
api.Seed(Today, "von mir");
|
||||
api.Seed(Today, "von Claude", fromAgent: true);
|
||||
});
|
||||
|
||||
Assert.False(Bullets(vm)[0].FromAgent);
|
||||
Assert.True(Bullets(vm)[1].FromAgent);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user