Skip to content

Commit 74ca985

Browse files
Neil DcruzeNeil Dcruze
authored andcommitted
updated the CLI to use the kernel app list style format for profiles
1 parent 0394312 commit 74ca985

2 files changed

Lines changed: 102 additions & 23 deletions

File tree

cmd/profiles.go

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/kernel/kernel-go-sdk/option"
1515
"github.com/kernel/kernel-go-sdk/packages/pagination"
1616
"github.com/pterm/pterm"
17+
"github.com/samber/lo"
1718
"github.com/spf13/cobra"
1819
)
1920

@@ -32,10 +33,10 @@ type ProfilesGetInput struct {
3233
}
3334

3435
type ProfilesListInput struct {
35-
Output string
36-
Limit int
37-
Offset int
38-
Query string
36+
Output string
37+
Page int
38+
PerPage int
39+
Query string
3940
}
4041

4142
type ProfilesCreateInput struct {
@@ -64,31 +65,42 @@ func (p ProfilesCmd) List(ctx context.Context, in ProfilesListInput) error {
6465
return fmt.Errorf("unsupported --output value: use 'json'")
6566
}
6667

68+
page := in.Page
69+
perPage := in.PerPage
70+
if page <= 0 {
71+
page = 1
72+
}
73+
if perPage <= 0 {
74+
perPage = 20
75+
}
76+
6777
if in.Output != "json" {
6878
pterm.Info.Println("Fetching profiles...")
6979
}
7080

7181
params := kernel.ProfileListParams{}
72-
if in.Limit > 0 {
73-
params.Limit = kernel.Opt(int64(in.Limit))
74-
}
75-
if in.Offset > 0 {
76-
params.Offset = kernel.Opt(int64(in.Offset))
77-
}
7882
if in.Query != "" {
7983
params.Query = kernel.Opt(in.Query)
8084
}
85+
params.Limit = kernel.Opt(int64(perPage + 1))
86+
params.Offset = kernel.Opt(int64((page - 1) * perPage))
8187

82-
page, err := p.profiles.List(ctx, params)
88+
result, err := p.profiles.List(ctx, params)
8389
if err != nil {
8490
return util.CleanedUpSdkError{Err: err}
8591
}
8692

8793
var items []kernel.Profile
88-
if page != nil {
89-
items = page.Items
94+
if result != nil {
95+
items = result.Items
9096
}
9197

98+
hasMore := len(items) > perPage
99+
if hasMore {
100+
items = items[:perPage]
101+
}
102+
itemsThisPage := len(items)
103+
92104
if in.Output == "json" {
93105
if len(items) == 0 {
94106
fmt.Println("[]")
@@ -116,6 +128,17 @@ func (p ProfilesCmd) List(ctx context.Context, in ProfilesListInput) error {
116128
})
117129
}
118130
PrintTableNoPad(rows, true)
131+
132+
pterm.Printf("\nPage: %d Per-page: %d Items this page: %d Has more: %s\n", page, perPage, itemsThisPage, lo.Ternary(hasMore, "yes", "no"))
133+
if hasMore {
134+
nextPage := page + 1
135+
nextCmd := fmt.Sprintf("kernel profile list --page %d --per-page %d", nextPage, perPage)
136+
if in.Query != "" {
137+
nextCmd += fmt.Sprintf(" --query \"%s\"", in.Query)
138+
}
139+
pterm.Printf("Next: %s\n", nextCmd)
140+
}
141+
119142
return nil
120143
}
121144

@@ -320,8 +343,8 @@ func init() {
320343
profilesCmd.AddCommand(profilesDownloadCmd)
321344

322345
profilesListCmd.Flags().StringP("output", "o", "", "Output format: json for raw API response")
323-
profilesListCmd.Flags().Int("limit", 0, "Maximum number of results to return")
324-
profilesListCmd.Flags().Int("offset", 0, "Number of results to skip")
346+
profilesListCmd.Flags().Int("per-page", 20, "Items per page (default 20)")
347+
profilesListCmd.Flags().Int("page", 1, "Page number (1-based)")
325348
profilesListCmd.Flags().String("query", "", "Search profiles by name or ID")
326349
profilesGetCmd.Flags().StringP("output", "o", "", "Output format: json for raw API response")
327350
profilesCreateCmd.Flags().StringP("output", "o", "", "Output format: json for raw API response")
@@ -334,16 +357,17 @@ func init() {
334357
func runProfilesList(cmd *cobra.Command, args []string) error {
335358
client := getKernelClient(cmd)
336359
output, _ := cmd.Flags().GetString("output")
337-
limit, _ := cmd.Flags().GetInt("limit")
338-
offset, _ := cmd.Flags().GetInt("offset")
360+
perPage, _ := cmd.Flags().GetInt("per-page")
361+
page, _ := cmd.Flags().GetInt("page")
339362
query, _ := cmd.Flags().GetString("query")
363+
340364
svc := client.Profiles
341365
p := ProfilesCmd{profiles: &svc}
342366
return p.List(cmd.Context(), ProfilesListInput{
343-
Output: output,
344-
Limit: limit,
345-
Offset: offset,
346-
Query: query,
367+
Output: output,
368+
Page: page,
369+
PerPage: perPage,
370+
Query: query,
347371
})
348372
}
349373

cmd/profiles_test.go

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"context"
66
"errors"
7+
"fmt"
78
"io"
89
"net/http"
910
"os"
@@ -86,7 +87,7 @@ func TestProfilesList_Empty(t *testing.T) {
8687
buf := captureProfilesOutput(t)
8788
fake := &FakeProfilesService{}
8889
p := ProfilesCmd{profiles: fake}
89-
_ = p.List(context.Background(), ProfilesListInput{})
90+
_ = p.List(context.Background(), ProfilesListInput{Page: 1, PerPage: 20})
9091
assert.Contains(t, buf.String(), "No profiles found")
9192
}
9293

@@ -98,11 +99,65 @@ func TestProfilesList_WithRows(t *testing.T) {
9899
return &pagination.OffsetPagination[kernel.Profile]{Items: rows}, nil
99100
}}
100101
p := ProfilesCmd{profiles: fake}
101-
_ = p.List(context.Background(), ProfilesListInput{})
102+
_ = p.List(context.Background(), ProfilesListInput{Page: 1, PerPage: 20})
102103
out := buf.String()
103104
assert.Contains(t, out, "p1")
104105
assert.Contains(t, out, "alpha")
105106
assert.Contains(t, out, "p2")
107+
assert.Contains(t, out, "Has more: no")
108+
}
109+
110+
func TestProfilesList_HasMore(t *testing.T) {
111+
buf := captureProfilesOutput(t)
112+
created := time.Unix(0, 0)
113+
perPage := 2
114+
items := make([]kernel.Profile, perPage+1)
115+
for i := range items {
116+
items[i] = kernel.Profile{ID: fmt.Sprintf("p%d", i), CreatedAt: created, UpdatedAt: created}
117+
}
118+
fake := &FakeProfilesService{ListFunc: func(ctx context.Context, query kernel.ProfileListParams, opts ...option.RequestOption) (*pagination.OffsetPagination[kernel.Profile], error) {
119+
return &pagination.OffsetPagination[kernel.Profile]{Items: items}, nil
120+
}}
121+
p := ProfilesCmd{profiles: fake}
122+
_ = p.List(context.Background(), ProfilesListInput{Page: 1, PerPage: perPage})
123+
out := buf.String()
124+
assert.Contains(t, out, "Has more: yes")
125+
assert.Contains(t, out, "Next: kernel profile list --page 2 --per-page 2")
126+
assert.Contains(t, out, "p0")
127+
assert.Contains(t, out, "p1")
128+
assert.NotContains(t, out, "p2")
129+
}
130+
131+
func TestProfilesList_QueryInNextHint(t *testing.T) {
132+
buf := captureProfilesOutput(t)
133+
created := time.Unix(0, 0)
134+
items := make([]kernel.Profile, 3)
135+
for i := range items {
136+
items[i] = kernel.Profile{ID: fmt.Sprintf("p%d", i), CreatedAt: created, UpdatedAt: created}
137+
}
138+
fake := &FakeProfilesService{ListFunc: func(ctx context.Context, query kernel.ProfileListParams, opts ...option.RequestOption) (*pagination.OffsetPagination[kernel.Profile], error) {
139+
return &pagination.OffsetPagination[kernel.Profile]{Items: items}, nil
140+
}}
141+
p := ProfilesCmd{profiles: fake}
142+
_ = p.List(context.Background(), ProfilesListInput{Page: 1, PerPage: 2, Query: "my-bot"})
143+
out := buf.String()
144+
assert.Contains(t, out, `--query "my-bot"`)
145+
}
146+
147+
func TestProfilesList_QueryWithSpacesQuoted(t *testing.T) {
148+
buf := captureProfilesOutput(t)
149+
created := time.Unix(0, 0)
150+
items := make([]kernel.Profile, 3)
151+
for i := range items {
152+
items[i] = kernel.Profile{ID: fmt.Sprintf("p%d", i), CreatedAt: created, UpdatedAt: created}
153+
}
154+
fake := &FakeProfilesService{ListFunc: func(ctx context.Context, query kernel.ProfileListParams, opts ...option.RequestOption) (*pagination.OffsetPagination[kernel.Profile], error) {
155+
return &pagination.OffsetPagination[kernel.Profile]{Items: items}, nil
156+
}}
157+
p := ProfilesCmd{profiles: fake}
158+
_ = p.List(context.Background(), ProfilesListInput{Page: 1, PerPage: 2, Query: "my bot"})
159+
out := buf.String()
160+
assert.Contains(t, out, `--query "my bot"`)
106161
}
107162

108163
func TestProfilesGet_Success(t *testing.T) {

0 commit comments

Comments
 (0)