feat(tui): add link picker and navigation history
CI / test (pull_request) Successful in 2m18s

Press [ in detail view to open link picker showing all [[links]]
in the current entry. Enter follows a link, resolving by title
then body substring. Navigation history stack enables esc to pop
back through followed links before returning to list.

Adds Store.ResolveLink() for non-transactional link resolution
from the TUI layer.
This commit is contained in:
2026-05-21 14:03:09 -04:00
parent 8426c2fbc1
commit 2684eb1d24
6 changed files with 201 additions and 0 deletions
+47
View File
@@ -223,3 +223,50 @@ func TestSyncLinks_DeletedSourceHidden(t *testing.T) {
t.Fatalf("soft-deleted source should not appear in backlinks, got %d", len(backlinks))
}
}
func TestResolveLink_TitleMatch(t *testing.T) {
s := testStore(t)
ctx := context.Background()
title := "nginx config"
target := &Entity{Body: "proxy_pass details", Title: &title, Glyph: "note", Tags: []string{}}
if err := s.Create(ctx, target); err != nil {
t.Fatal(err)
}
resolved, err := s.ResolveLink(ctx, "nginx config")
if err != nil {
t.Fatal(err)
}
if resolved.ID != target.ID {
t.Errorf("resolved ID = %s, want %s", resolved.ID, target.ID)
}
}
func TestResolveLink_BodyFallback(t *testing.T) {
s := testStore(t)
ctx := context.Background()
target := &Entity{Body: "deploy staging checklist", Glyph: "note", Tags: []string{}}
if err := s.Create(ctx, target); err != nil {
t.Fatal(err)
}
resolved, err := s.ResolveLink(ctx, "deploy staging")
if err != nil {
t.Fatal(err)
}
if resolved.ID != target.ID {
t.Errorf("resolved ID = %s, want %s", resolved.ID, target.ID)
}
}
func TestResolveLink_NotFound(t *testing.T) {
s := testStore(t)
ctx := context.Background()
_, err := s.ResolveLink(ctx, "nonexistent entry")
if err != ErrNotFound {
t.Errorf("expected ErrNotFound, got %v", err)
}
}