Skip to content

feat(tui): jot target indicator and entry detail refresh - #18

Merged
chris-regnier merged 3 commits into
mainfrom
feature/context-aware-jot
Feb 28, 2026
Merged

feat(tui): jot target indicator and entry detail refresh#18
chris-regnier merged 3 commits into
mainfrom
feature/context-aware-jot

Conversation

@chris-regnier

Copy link
Copy Markdown
Owner

Summary

  • Show a "Jotting into: ..." indicator label above the jot textarea so users know which entry they're appending to
  • Fix jot completion on the entry detail screen to refresh the displayed entry from the store
  • Add integration test for jot-into-selected-entry on the today screen

Test plan

  • All 71 UI tests pass (task test)
  • Build succeeds (task build)
  • Gavel analysis clean on Go diff

🤖 Generated with Claude Code

chris-regnier and others added 3 commits February 28, 2026 07:53
Displays "Jotting into: # Meeting Notes" (or similar) above the jot
textarea so the user knows which entry will receive the jot.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add screenEntryDetail case to jotCompleteMsg handler so the viewport
reloads after jotting into a viewed entry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment thread internal/ui/picker.go
// Reload day detail by reinitializing on current screen
return m.loadDayDetail()
case screenEntryDetail:
return m.loadEntryDetail(m.entry.ID)

Check failure

Code scanning / gavel

Detect critical bugs, logic errors, and potential runtime failures Error

Potential null pointer dereference when accessing m.entry.ID without null check.
Comment thread internal/ui/picker.go
func (m pickerModel) jotTargetLabel() string {
if m.jotTarget == nil {
return "Jotting into: new entry"
}

Check warning

Code scanning / gavel

Identify code smells that impact maintainability and readability Warning

Magic number 40 used for preview truncation without explanation.
Comment on lines +1809 to +1812

func TestJotTargetIndicator(t *testing.T) {
now := time.Now()
today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)

Check warning

Code scanning / gavel

Assess test quality, coverage gaps, and testing best practices Warning test

Test uses hard-coded time constants that could make assertions brittle and timing-dependent.
Comment on lines +1815 to +1871
ID: "other01",
Content: "# Meeting Notes\n\nSome notes",
CreatedAt: today.Add(10 * time.Hour),
UpdatedAt: today.Add(10 * time.Hour),
}

store := &mockStorage{
entries: map[string][]entry.Entry{
today.Format("2006-01-02"): {otherEntry},
},
byID: map[string]entry.Entry{
"other01": otherEntry,
},
}

cfg := TUIConfig{Editor: "vi", DefaultTemplate: "", Theme: presets["default-dark"]}
m := newTUIModel(store, cfg)
m.screen = screenToday
m.todayFocus = focusEntryList
sized, _ := m.Update(tea.WindowSizeMsg{Width: 80, Height: 24})
m = sized.(pickerModel)

// Set up entry list
items := []list.Item{entryItem{entry: otherEntry}}
m.todayList = list.New(items, list.NewDefaultDelegate(), 80, 20)

// Start jot — target should be otherEntry
started, _ := m.startJot()
m = started.(pickerModel)

view := m.View()
stripped := stripANSI(view)
if !strings.Contains(stripped, "Jotting into:") {
t.Error("Expected 'Jotting into:' indicator in view")
}
if !strings.Contains(stripped, "Meeting Notes") {
t.Error("Expected target entry preview in jot indicator")
}
}

func TestJotFromEntryDetail_RefreshesEntry(t *testing.T) {
now := time.Now()
today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)

viewedEntry := entry.Entry{
ID: "viewed01",
Content: "# Viewed Entry\n\nOriginal content",
CreatedAt: today.Add(10 * time.Hour),
UpdatedAt: today.Add(10 * time.Hour),
}

// Store has an updated version of the entry (simulating post-jot state)
updatedEntry := viewedEntry
updatedEntry.Content = "# Viewed Entry\n\nOriginal content\n- **14:00** new jot"

store := &mockStorage{
entries: map[string][]entry.Entry{

Check warning

Code scanning / gavel

Identify code smells that impact maintainability and readability Warning test

Repeated mock storage setup pattern should be extracted into a test helper function.
Comment on lines +1841 to +1846
// Start jot — target should be otherEntry
started, _ := m.startJot()
m = started.(pickerModel)

view := m.View()
stripped := stripANSI(view)

Check warning

Code scanning / gavel

Assess test quality, coverage gaps, and testing best practices Warning test

Test assertions are too vague and could pass even if the feature is partially broken.
Comment on lines +1899 to +1964
func TestJotIntoSelectedEntry_TodayScreen(t *testing.T) {
now := time.Now()
today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)

dailyEntry := entry.Entry{
ID: "daily01",
Content: "# Daily\n\nDaily content",
CreatedAt: today.Add(8 * time.Hour),
UpdatedAt: today.Add(8 * time.Hour),
}
otherEntry := entry.Entry{
ID: "other01",
Content: "# Side Notes",
CreatedAt: today.Add(10 * time.Hour),
UpdatedAt: today.Add(10 * time.Hour),
}

store := &mockStorage{
entries: map[string][]entry.Entry{
today.Format("2006-01-02"): {otherEntry, dailyEntry},
},
byID: map[string]entry.Entry{
"daily01": dailyEntry,
"other01": otherEntry,
},
}

cfg := TUIConfig{Editor: "vi", DefaultTemplate: ""}
m := newTUIModel(store, cfg)
m.screen = screenToday
m.dailyEntry = &dailyEntry
m.todayFocus = focusEntryList
sized, _ := m.Update(tea.WindowSizeMsg{Width: 80, Height: 24})
m = sized.(pickerModel)

// Set up entry list with other entry selected
items := []list.Item{entryItem{entry: otherEntry}}
m.todayList = list.New(items, list.NewDefaultDelegate(), 80, 20)

// Start jot
started, _ := m.startJot()
m = started.(pickerModel)
m.jotInput.SetValue("Quick thought")

// Submit
updatedModel, cmd := m.updateJotInput(tea.KeyMsg{Type: tea.KeyEnter})
m = updatedModel.(pickerModel)

if cmd == nil {
t.Fatal("Expected jot command")
}

result := cmd()
if jotMsg, ok := result.(jotCompleteMsg); ok {
if jotMsg.err != nil {
t.Fatalf("Jot failed: %v", jotMsg.err)
}
}

// Verify jot went to other01
updated := store.byID["other01"]
if !strings.Contains(updated.Content, "Quick thought") {
t.Errorf("Expected jot in other01, content: %s", updated.Content)
}

// Verify daily was NOT modified

Check warning

Code scanning / gavel

Assess test quality, coverage gaps, and testing best practices Warning test

Missing error path testing for jot operations.
@chris-regnier
chris-regnier merged commit ab2286e into main Feb 28, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants