Skip to content

Commit 900f94d

Browse files
authored
Add summary field to JSON responses (#42)
Add a human-readable summary field to list and show commands that provides quick feedback about the response data (e.g., "5 boards", "Card #123: Fix login bug", "7 results for \"bug\""). The summary adapts to pagination flags and includes contextual details like unread counts for notifications.
1 parent d9b09c0 commit 900f94d

12 files changed

Lines changed: 210 additions & 11 deletions

File tree

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,23 @@ Command results output JSON. (`--help` and `--version` output plain text.)
482482
}
483483
```
484484

485+
### Summary Field
486+
487+
List and show commands include a `summary` field with a human-readable description of the response. This is useful for quick feedback in scripts or when piping output.
488+
489+
```bash
490+
fizzy board list | jq -r '.summary'
491+
# "5 boards"
492+
493+
fizzy card list --board ABC --all | jq -r '.summary'
494+
# "42 cards (all)"
495+
496+
fizzy search "bug" | jq -r '.summary'
497+
# "7 results for \"bug\""
498+
```
499+
500+
The summary adapts to pagination flags (`--page N` or `--all`) and includes contextual details like unread counts for notifications.
501+
485502
When creating resources, the CLI automatically follows the `Location` header to fetch the complete resource data:
486503

487504
```json

internal/commands/board.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package commands
22

33
import (
4+
"fmt"
5+
46
"github.com/robzolkos/fizzy-cli/internal/errors"
57
"github.com/spf13/cobra"
68
)
@@ -35,8 +37,20 @@ var boardListCmd = &cobra.Command{
3537
exitWithError(err)
3638
}
3739

40+
// Build summary
41+
count := 0
42+
if arr, ok := resp.Data.([]interface{}); ok {
43+
count = len(arr)
44+
}
45+
summary := fmt.Sprintf("%d boards", count)
46+
if boardListAll {
47+
summary += " (all)"
48+
} else if boardListPage > 0 {
49+
summary += fmt.Sprintf(" (page %d)", boardListPage)
50+
}
51+
3852
hasNext := resp.LinkNext != ""
39-
printSuccessWithPagination(resp.Data, hasNext, resp.LinkNext)
53+
printSuccessWithPaginationAndSummary(resp.Data, hasNext, resp.LinkNext, summary)
4054
},
4155
}
4256

@@ -56,7 +70,15 @@ var boardShowCmd = &cobra.Command{
5670
exitWithError(err)
5771
}
5872

59-
printSuccess(resp.Data)
73+
// Build summary
74+
summary := "Board"
75+
if board, ok := resp.Data.(map[string]interface{}); ok {
76+
if name, ok := board["name"].(string); ok {
77+
summary = fmt.Sprintf("Board: %s", name)
78+
}
79+
}
80+
81+
printSuccessWithSummary(resp.Data, summary)
6082
},
6183
}
6284

internal/commands/card.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package commands
22

33
import (
4+
"fmt"
45
"os"
56
"strconv"
67
"strings"
@@ -173,8 +174,20 @@ var cardListCmd = &cobra.Command{
173174
resp.Data = filtered
174175
}
175176

177+
// Build summary
178+
count := 0
179+
if arr, ok := resp.Data.([]interface{}); ok {
180+
count = len(arr)
181+
}
182+
summary := fmt.Sprintf("%d cards", count)
183+
if cardListAll {
184+
summary += " (all)"
185+
} else if cardListPage > 0 {
186+
summary += fmt.Sprintf(" (page %d)", cardListPage)
187+
}
188+
176189
hasNext := resp.LinkNext != ""
177-
printSuccessWithPagination(resp.Data, hasNext, resp.LinkNext)
190+
printSuccessWithPaginationAndSummary(resp.Data, hasNext, resp.LinkNext, summary)
178191
},
179192
}
180193

@@ -194,7 +207,15 @@ var cardShowCmd = &cobra.Command{
194207
exitWithError(err)
195208
}
196209

197-
printSuccess(resp.Data)
210+
// Build summary
211+
summary := fmt.Sprintf("Card #%s", args[0])
212+
if card, ok := resp.Data.(map[string]interface{}); ok {
213+
if title, ok := card["title"].(string); ok {
214+
summary = fmt.Sprintf("Card #%s: %s", args[0], title)
215+
}
216+
}
217+
218+
printSuccessWithSummary(resp.Data, summary)
198219
},
199220
}
200221

internal/commands/column.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package commands
22

33
import (
4+
"fmt"
5+
46
"github.com/robzolkos/fizzy-cli/internal/errors"
57
"github.com/spf13/cobra"
68
)
@@ -45,7 +47,10 @@ var columnListCmd = &cobra.Command{
4547
cols = append(cols, data...)
4648
cols = append(cols, pseudoColumnObject(pseudoColumnDone))
4749

48-
printSuccess(cols)
50+
// Build summary
51+
summary := fmt.Sprintf("%d columns", len(cols))
52+
53+
printSuccessWithSummary(cols, summary)
4954
},
5055
}
5156

internal/commands/comment.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package commands
22

33
import (
4+
"fmt"
45
"os"
56

67
"github.com/spf13/cobra"
@@ -41,8 +42,20 @@ var commentListCmd = &cobra.Command{
4142
exitWithError(err)
4243
}
4344

45+
// Build summary
46+
count := 0
47+
if arr, ok := resp.Data.([]interface{}); ok {
48+
count = len(arr)
49+
}
50+
summary := fmt.Sprintf("%d comments on card #%s", count, commentListCard)
51+
if commentListAll {
52+
summary += " (all)"
53+
} else if commentListPage > 0 {
54+
summary += fmt.Sprintf(" (page %d)", commentListPage)
55+
}
56+
4457
hasNext := resp.LinkNext != ""
45-
printSuccessWithPagination(resp.Data, hasNext, resp.LinkNext)
58+
printSuccessWithPaginationAndSummary(resp.Data, hasNext, resp.LinkNext, summary)
4659
},
4760
}
4861

internal/commands/notification.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package commands
22

33
import (
4+
"fmt"
45
"strconv"
56

67
"github.com/spf13/cobra"
@@ -36,8 +37,28 @@ var notificationListCmd = &cobra.Command{
3637
exitWithError(err)
3738
}
3839

40+
// Build summary with unread count
41+
count := 0
42+
unreadCount := 0
43+
if arr, ok := resp.Data.([]interface{}); ok {
44+
count = len(arr)
45+
for _, item := range arr {
46+
if notif, ok := item.(map[string]interface{}); ok {
47+
if read, ok := notif["read"].(bool); ok && !read {
48+
unreadCount++
49+
}
50+
}
51+
}
52+
}
53+
summary := fmt.Sprintf("%d notifications (%d unread)", count, unreadCount)
54+
if notificationListAll {
55+
summary = fmt.Sprintf("%d notifications (%d unread, all)", count, unreadCount)
56+
} else if notificationListPage > 0 {
57+
summary = fmt.Sprintf("%d notifications (%d unread, page %d)", count, unreadCount, notificationListPage)
58+
}
59+
3960
hasNext := resp.LinkNext != ""
40-
printSuccessWithPagination(resp.Data, hasNext, resp.LinkNext)
61+
printSuccessWithPaginationAndSummary(resp.Data, hasNext, resp.LinkNext, summary)
4162
},
4263
}
4364

internal/commands/reaction.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package commands
22

33
import (
4+
"fmt"
5+
46
"github.com/spf13/cobra"
57
)
68

@@ -36,7 +38,14 @@ var reactionListCmd = &cobra.Command{
3638
exitWithError(err)
3739
}
3840

39-
printSuccess(resp.Data)
41+
// Build summary
42+
count := 0
43+
if arr, ok := resp.Data.([]interface{}); ok {
44+
count = len(arr)
45+
}
46+
summary := fmt.Sprintf("%d reactions on comment", count)
47+
48+
printSuccessWithSummary(resp.Data, summary)
4049
},
4150
}
4251

internal/commands/root.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,30 @@ func printSuccessWithPagination(data interface{}, hasNext bool, nextURL string)
206206
os.Exit(errors.ExitSuccess)
207207
}
208208

209+
// printSuccessWithSummary prints a success response with summary.
210+
func printSuccessWithSummary(data interface{}, summary string) {
211+
resp := response.SuccessWithSummary(data, summary)
212+
if lastResult != nil {
213+
lastResult.Response = resp
214+
lastResult.ExitCode = errors.ExitSuccess
215+
panic(testExitSignal{}) // Signal to stop execution in test mode
216+
}
217+
resp.Print()
218+
os.Exit(errors.ExitSuccess)
219+
}
220+
221+
// printSuccessWithPaginationAndSummary prints a success response with pagination and summary.
222+
func printSuccessWithPaginationAndSummary(data interface{}, hasNext bool, nextURL string, summary string) {
223+
resp := response.SuccessWithPaginationAndSummary(data, hasNext, nextURL, summary)
224+
if lastResult != nil {
225+
lastResult.Response = resp
226+
lastResult.ExitCode = errors.ExitSuccess
227+
panic(testExitSignal{}) // Signal to stop execution in test mode
228+
}
229+
resp.Print()
230+
os.Exit(errors.ExitSuccess)
231+
}
232+
209233
// SetTestMode configures the commands package for testing.
210234
// It sets a mock client factory and captures results instead of exiting.
211235
func SetTestMode(mockClient client.API) *CommandResult {

internal/commands/search.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package commands
22

33
import (
4+
"fmt"
45
"strconv"
56
"strings"
67

@@ -68,8 +69,20 @@ var searchCmd = &cobra.Command{
6869
exitWithError(err)
6970
}
7071

72+
// Build summary
73+
count := 0
74+
if arr, ok := resp.Data.([]interface{}); ok {
75+
count = len(arr)
76+
}
77+
summary := fmt.Sprintf("%d results for \"%s\"", count, query)
78+
if searchAll {
79+
summary = fmt.Sprintf("%d results for \"%s\" (all)", count, query)
80+
} else if searchPage > 0 {
81+
summary = fmt.Sprintf("%d results for \"%s\" (page %d)", count, query, searchPage)
82+
}
83+
7184
hasNext := resp.LinkNext != ""
72-
printSuccessWithPagination(resp.Data, hasNext, resp.LinkNext)
85+
printSuccessWithPaginationAndSummary(resp.Data, hasNext, resp.LinkNext, summary)
7386
},
7487
}
7588

internal/commands/tag.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package commands
22

33
import (
4+
"fmt"
45
"strconv"
56

67
"github.com/spf13/cobra"
@@ -36,8 +37,20 @@ var tagListCmd = &cobra.Command{
3637
exitWithError(err)
3738
}
3839

40+
// Build summary
41+
count := 0
42+
if arr, ok := resp.Data.([]interface{}); ok {
43+
count = len(arr)
44+
}
45+
summary := fmt.Sprintf("%d tags", count)
46+
if tagListAll {
47+
summary += " (all)"
48+
} else if tagListPage > 0 {
49+
summary += fmt.Sprintf(" (page %d)", tagListPage)
50+
}
51+
3952
hasNext := resp.LinkNext != ""
40-
printSuccessWithPagination(resp.Data, hasNext, resp.LinkNext)
53+
printSuccessWithPaginationAndSummary(resp.Data, hasNext, resp.LinkNext, summary)
4154
},
4255
}
4356

0 commit comments

Comments
 (0)