Skip to content

Commit abeaaf4

Browse files
authored
Browser pools cli polish pass (#47)
## Overview - Enhances `kernel pools get ...` to have much more information - Adds formatting utils ## Testing CI + ran `./scripts/test-browser-pools.sh` against staging Example output: <img width="867" height="224" alt="image" src="https://github.com/user-attachments/assets/159207ba-9475-4a43-a25c-63ea267efa88" />
1 parent 502c042 commit abeaaf4

File tree

3 files changed

+115
-29
lines changed

3 files changed

+115
-29
lines changed

cmd/browser_pools.go

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,9 @@ func (c BrowserPoolsCmd) List(ctx context.Context, in BrowserPoolsListInput) err
6767
}
6868

6969
for _, p := range *pools {
70-
name := p.Name
71-
if name == "" {
72-
name = "-"
73-
}
7470
tableData = append(tableData, []string{
7571
p.ID,
76-
name,
72+
util.OrDash(p.Name),
7773
fmt.Sprintf("%d", p.AvailableCount),
7874
fmt.Sprintf("%d", p.AcquiredCount),
7975
util.FormatLocal(p.CreatedAt),
@@ -125,7 +121,6 @@ func (c BrowserPoolsCmd) Create(ctx context.Context, in BrowserPoolsCreateInput)
125121
req.KioskMode = kernel.Bool(in.Kiosk.Value)
126122
}
127123

128-
// Profile
129124
profile, err := buildProfileParam(in.ProfileID, in.ProfileName, in.ProfileSaveChanges)
130125
if err != nil {
131126
pterm.Error.Println(err.Error())
@@ -139,10 +134,8 @@ func (c BrowserPoolsCmd) Create(ctx context.Context, in BrowserPoolsCreateInput)
139134
req.ProxyID = kernel.String(in.ProxyID)
140135
}
141136

142-
// Extensions
143137
req.Extensions = buildExtensionsParam(in.Extensions)
144138

145-
// Viewport
146139
viewport, err := buildViewportParam(in.Viewport)
147140
if err != nil {
148141
pterm.Error.Println(err.Error())
@@ -194,21 +187,28 @@ func (c BrowserPoolsCmd) Get(ctx context.Context, in BrowserPoolsGetInput) error
194187
return nil
195188
}
196189

197-
name := pool.Name
198-
if name == "" {
199-
name = "-"
200-
}
201-
tableData := pterm.TableData{
190+
cfg := pool.BrowserPoolConfig
191+
192+
rows := pterm.TableData{
202193
{"Property", "Value"},
203194
{"ID", pool.ID},
204-
{"Name", name},
205-
{"Size", fmt.Sprintf("%d", pool.BrowserPoolConfig.Size)},
195+
{"Name", util.OrDash(pool.Name)},
196+
{"Created At", util.FormatLocal(pool.CreatedAt)},
197+
{"Size", fmt.Sprintf("%d", cfg.Size)},
206198
{"Available", fmt.Sprintf("%d", pool.AvailableCount)},
207199
{"Acquired", fmt.Sprintf("%d", pool.AcquiredCount)},
208-
{"Timeout", fmt.Sprintf("%d", pool.BrowserPoolConfig.TimeoutSeconds)},
209-
{"Created At", util.FormatLocal(pool.CreatedAt)},
210-
}
211-
PrintTableNoPad(tableData, true)
200+
{"Fill Rate", formatFillRate(cfg.FillRatePerMinute)},
201+
{"Timeout", fmt.Sprintf("%d seconds", cfg.TimeoutSeconds)},
202+
{"Headless", fmt.Sprintf("%t", cfg.Headless)},
203+
{"Stealth", fmt.Sprintf("%t", cfg.Stealth)},
204+
{"Kiosk Mode", fmt.Sprintf("%t", cfg.KioskMode)},
205+
{"Profile", formatProfile(cfg.Profile)},
206+
{"Proxy ID", util.OrDash(cfg.ProxyID)},
207+
{"Extensions", formatExtensions(cfg.Extensions)},
208+
{"Viewport", formatViewport(cfg.Viewport)},
209+
}
210+
211+
PrintTableNoPad(rows, true)
212212
return nil
213213
}
214214

@@ -258,7 +258,6 @@ func (c BrowserPoolsCmd) Update(ctx context.Context, in BrowserPoolsUpdateInput)
258258
req.DiscardAllIdle = kernel.Bool(in.DiscardAllIdle.Value)
259259
}
260260

261-
// Profile
262261
profile, err := buildProfileParam(in.ProfileID, in.ProfileName, in.ProfileSaveChanges)
263262
if err != nil {
264263
pterm.Error.Println(err.Error())
@@ -272,10 +271,8 @@ func (c BrowserPoolsCmd) Update(ctx context.Context, in BrowserPoolsUpdateInput)
272271
req.ProxyID = kernel.String(in.ProxyID)
273272
}
274273

275-
// Extensions
276274
req.Extensions = buildExtensionsParam(in.Extensions)
277275

278-
// Viewport
279276
viewport, err := buildViewportParam(in.Viewport)
280277
if err != nil {
281278
pterm.Error.Println(err.Error())
@@ -450,10 +447,8 @@ var browserPoolsFlushCmd = &cobra.Command{
450447
}
451448

452449
func init() {
453-
// list flags
454450
browserPoolsListCmd.Flags().StringP("output", "o", "", "Output format: json for raw API response")
455451

456-
// create flags
457452
browserPoolsCreateCmd.Flags().String("name", "", "Optional unique name for the pool")
458453
browserPoolsCreateCmd.Flags().Int64("size", 0, "Number of browsers in the pool")
459454
_ = browserPoolsCreateCmd.MarkFlagRequired("size")
@@ -469,10 +464,8 @@ func init() {
469464
browserPoolsCreateCmd.Flags().StringSlice("extension", []string{}, "Extension IDs or names")
470465
browserPoolsCreateCmd.Flags().String("viewport", "", "Viewport size (e.g. 1280x800)")
471466

472-
// get flags
473467
browserPoolsGetCmd.Flags().StringP("output", "o", "", "Output format: json for raw API response")
474468

475-
// update flags
476469
browserPoolsUpdateCmd.Flags().String("name", "", "Update the pool name")
477470
browserPoolsUpdateCmd.Flags().Int64("size", 0, "Number of browsers in the pool")
478471
browserPoolsUpdateCmd.Flags().Int64("fill-rate", 0, "Fill rate per minute")
@@ -488,13 +481,10 @@ func init() {
488481
browserPoolsUpdateCmd.Flags().String("viewport", "", "Viewport size (e.g. 1280x800)")
489482
browserPoolsUpdateCmd.Flags().Bool("discard-all-idle", false, "Discard all idle browsers")
490483

491-
// delete flags
492484
browserPoolsDeleteCmd.Flags().Bool("force", false, "Force delete even if browsers are leased")
493485

494-
// acquire flags
495486
browserPoolsAcquireCmd.Flags().Int64("timeout", 0, "Acquire timeout in seconds")
496487

497-
// release flags
498488
browserPoolsReleaseCmd.Flags().String("session-id", "", "Browser session ID to release")
499489
_ = browserPoolsReleaseCmd.MarkFlagRequired("session-id")
500490
browserPoolsReleaseCmd.Flags().Bool("reuse", true, "Reuse the browser instance")
@@ -692,3 +682,42 @@ func buildViewportParam(viewport string) (*kernel.BrowserViewportParam, error) {
692682
}
693683
return &vp, nil
694684
}
685+
686+
func formatFillRate(rate int64) string {
687+
if rate > 0 {
688+
return fmt.Sprintf("%d%%", rate)
689+
}
690+
return "-"
691+
}
692+
693+
func formatProfile(profile kernel.BrowserProfile) string {
694+
name := util.FirstOrDash(profile.Name, profile.ID)
695+
if name == "-" {
696+
return "-"
697+
}
698+
if profile.SaveChanges {
699+
return fmt.Sprintf("%s (save changes: true)", name)
700+
}
701+
return fmt.Sprintf("%s (save changes: false)", name)
702+
}
703+
704+
func formatExtensions(extensions []kernel.BrowserExtension) string {
705+
var names []string
706+
for _, ext := range extensions {
707+
if name := util.FirstOrDash(ext.Name, ext.ID); name != "-" {
708+
names = append(names, name)
709+
}
710+
}
711+
return util.JoinOrDash(names...)
712+
}
713+
714+
func formatViewport(viewport kernel.BrowserViewport) string {
715+
if viewport.Width == 0 || viewport.Height == 0 {
716+
return "-"
717+
}
718+
s := fmt.Sprintf("%dx%d", viewport.Width, viewport.Height)
719+
if viewport.RefreshRate > 0 {
720+
s += fmt.Sprintf("@%d", viewport.RefreshRate)
721+
}
722+
return s
723+
}

pkg/util/format.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package util
2+
3+
import "strings"
4+
5+
// OrDash returns the string if non-empty, otherwise returns "-".
6+
func OrDash(s string) string {
7+
if s == "" {
8+
return "-"
9+
}
10+
return s
11+
}
12+
13+
// FirstOrDash returns the first non-empty string from the provided items.
14+
// If all items are empty, it returns "-".
15+
func FirstOrDash(items ...string) string {
16+
for _, item := range items {
17+
if item != "" {
18+
return item
19+
}
20+
}
21+
return "-"
22+
}
23+
24+
// JoinOrDash joins the provided strings with ", " as separator.
25+
// If no items are provided, it returns "-".
26+
func JoinOrDash(items ...string) string {
27+
if len(items) == 0 {
28+
return "-"
29+
}
30+
return strings.Join(items, ", ")
31+
}

pkg/util/format_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package util
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestOrDash(t *testing.T) {
10+
assert.Equal(t, "hello", OrDash("hello"))
11+
assert.Equal(t, "-", OrDash(""))
12+
}
13+
14+
func TestFirstOrDash(t *testing.T) {
15+
assert.Equal(t, "first", FirstOrDash("first", "second", "third"))
16+
assert.Equal(t, "second", FirstOrDash("", "second", "third"))
17+
assert.Equal(t, "third", FirstOrDash("", "", "third"))
18+
assert.Equal(t, "-", FirstOrDash("", "", ""))
19+
assert.Equal(t, "-", FirstOrDash())
20+
}
21+
22+
func TestJoinOrDash(t *testing.T) {
23+
assert.Equal(t, "a, b, c", JoinOrDash("a", "b", "c"))
24+
assert.Equal(t, "a", JoinOrDash("a"))
25+
assert.Equal(t, "-", JoinOrDash())
26+
}

0 commit comments

Comments
 (0)