Skip to content

Commit ddf5edf

Browse files
authored
fix: fall back to summary when title is empty in formatCell (#380)
The reports/upcoming API uses the calendar partial (schedules/calendar/_entry.json.jbuilder) which emits summary but not title for schedule entries. The SDK deserializes the missing field to an empty string, so formatCell's existing name → title → id chain was appending "" for each entry and joining them into ", , , , ..." in --md and styled output. Add summary as a fallback between title and id, and add empty-string guards on the name and title checks so an empty field doesn't silently win over a non-empty one lower in the chain. Schedule::Entry#title delegates to summary in bc3, so the two fields carry identical data when both are present; summary is the canonical field in the calendar API response. Fixes: reports schedule --md showing blank entry names
1 parent d005961 commit ddf5edf

2 files changed

Lines changed: 32 additions & 3 deletions

File tree

internal/output/output_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,30 @@ func TestFormatCellWithMapArray(t *testing.T) {
870870
}
871871
result = formatCell(attachments)
872872
assert.Equal(t, "100, 200", result)
873+
874+
// Test maps with summary fallback (schedule entries: the reports/upcoming API
875+
// uses the calendar partial which emits summary but not title, so title arrives
876+
// as an empty string from the SDK zero-value; summary must win).
877+
entries := []any{
878+
map[string]any{"id": float64(1), "title": "", "summary": "Team standup"},
879+
map[string]any{"id": float64(2), "title": "", "summary": "Paul G OUT (Sabbatical)"},
880+
}
881+
result = formatCell(entries)
882+
assert.Equal(t, "Team standup, Paul G OUT (Sabbatical)", result)
883+
884+
// Test that a non-empty title still wins over summary.
885+
withBoth := []any{
886+
map[string]any{"id": float64(1), "title": "Explicit title", "summary": "Summary text"},
887+
}
888+
result = formatCell(withBoth)
889+
assert.Equal(t, "Explicit title", result)
890+
891+
// Test that an empty name does not shadow a valid title (empty-string guard).
892+
emptyName := []any{
893+
map[string]any{"id": float64(1), "name": "", "title": "A task"},
894+
}
895+
result = formatCell(emptyName)
896+
assert.Equal(t, "A task", result)
873897
}
874898

875899
// =============================================================================

internal/output/render.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -763,11 +763,16 @@ func formatCell(val any) string {
763763
case int, int64:
764764
items = append(items, fmt.Sprintf("%d", elem))
765765
case map[string]any:
766-
// Try name, then title, then id, then fallback
767-
if name, ok := elem["name"].(string); ok {
766+
// Try name → title → summary → id.
767+
// summary is checked after title because schedule entries omit title
768+
// from the calendar/reports API response and use summary as their
769+
// display name (Schedule::Entry#title delegates to summary in bc3).
770+
if name, ok := elem["name"].(string); ok && name != "" {
768771
items = append(items, ansi.Strip(name))
769-
} else if title, ok := elem["title"].(string); ok {
772+
} else if title, ok := elem["title"].(string); ok && title != "" {
770773
items = append(items, ansi.Strip(title))
774+
} else if summary, ok := elem["summary"].(string); ok && summary != "" {
775+
items = append(items, ansi.Strip(summary))
771776
} else if id, ok := elem["id"]; ok {
772777
items = append(items, fmt.Sprintf("%v", id))
773778
}

0 commit comments

Comments
 (0)