Skip to content

Commit be50bad

Browse files
authored
refactor(display): make identifier styling explicit (#68)
1 parent 58a2cc5 commit be50bad

9 files changed

Lines changed: 64 additions & 62 deletions

File tree

internal/commands/checkouts/checkouts.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,11 @@ func listCheckouts(ctx context.Context, cmd *cli.Command) error {
179179
})
180180
}
181181

182-
return display.RenderTable(
183-
appCtx.Output,
184-
"Checkouts",
185-
[]string{"ID", "Reference", "Amount", "Status", "Merchant", "Created At"},
186-
rows,
187-
)
182+
return display.RenderTableWithOptions(appCtx.Output, []string{"ID", "Reference", "Amount", "Status", "Merchant", "Created At"}, rows, display.TableOptions{
183+
Title: "Checkouts",
184+
EmptyText: "No items to display",
185+
IdentifierColumns: []int{0},
186+
})
188187
}
189188

190189
func createCheckout(ctx context.Context, cmd *cli.Command) error {
@@ -362,9 +361,9 @@ func listPaymentMethods(ctx context.Context, cmd *cli.Command) error {
362361
}
363362

364363
return display.RenderTableWithOptions(appCtx.Output, []string{"ID"}, rows, display.TableOptions{
365-
Title: "Checkout Payment Methods",
366-
EmptyText: "No payment methods available",
367-
HighlightIDColumns: true,
364+
Title: "Checkout Payment Methods",
365+
EmptyText: "No payment methods available",
366+
IdentifierColumns: []int{0},
368367
})
369368
}
370369

internal/commands/customers/customers.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -238,12 +238,11 @@ func listPaymentInstruments(ctx context.Context, cmd *cli.Command) error {
238238
})
239239
}
240240

241-
return display.RenderTable(
242-
appCtx.Output,
243-
"Payment Instruments",
244-
[]string{"Token", "Type", "Card", "Active", "Created At"},
245-
rows,
246-
)
241+
return display.RenderTableWithOptions(appCtx.Output, []string{"Token", "Type", "Card", "Active", "Created At"}, rows, display.TableOptions{
242+
Title: "Payment Instruments",
243+
EmptyText: "No items to display",
244+
IdentifierColumns: []int{0},
245+
})
247246
}
248247

249248
func deactivatePaymentInstrument(ctx context.Context, cmd *cli.Command) error {

internal/commands/members/members.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -227,12 +227,11 @@ func listMembers(ctx context.Context, cmd *cli.Command) error {
227227
})
228228
}
229229

230-
return display.RenderTable(
231-
appCtx.Output,
232-
"Members",
233-
[]string{"ID", "Email", "Roles", "Status", "Created At"},
234-
rows,
235-
)
230+
return display.RenderTableWithOptions(appCtx.Output, []string{"ID", "Email", "Roles", "Status", "Created At"}, rows, display.TableOptions{
231+
Title: "Members",
232+
EmptyText: "No items to display",
233+
IdentifierColumns: []int{0},
234+
})
236235
}
237236

238237
func createMember(ctx context.Context, cmd *cli.Command) error {

internal/commands/memberships/memberships.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,11 @@ func listMemberships(ctx context.Context, cmd *cli.Command) error {
117117
})
118118
}
119119

120-
return display.RenderTable(
121-
appCtx.Output,
122-
"Memberships",
123-
[]string{"ID", "Resource", "Type", "Roles", "Status", "Created At"},
124-
rows,
125-
)
120+
return display.RenderTableWithOptions(appCtx.Output, []string{"ID", "Resource", "Type", "Roles", "Status", "Created At"}, rows, display.TableOptions{
121+
Title: "Memberships",
122+
EmptyText: "No items to display",
123+
IdentifierColumns: []int{0},
124+
})
126125
}
127126

128127
func parseMembershipStatus(value string) (sumup.MembershipStatus, error) {

internal/commands/payouts/payouts.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,11 @@ func listPayouts(ctx context.Context, cmd *cli.Command) error {
117117
})
118118
}
119119

120-
return display.RenderTable(
121-
appCtx.Output,
122-
"Payouts",
123-
[]string{"ID", "Date", "Amount", "Fee", "Status", "Type", "Reference"},
124-
rows,
125-
)
120+
return display.RenderTableWithOptions(appCtx.Output, []string{"ID", "Date", "Amount", "Fee", "Status", "Type", "Reference"}, rows, display.TableOptions{
121+
Title: "Payouts",
122+
EmptyText: "No items to display",
123+
IdentifierColumns: []int{0},
124+
})
126125
}
127126

128127
func parseDateArg(value string) (datetime.Date, error) {

internal/commands/readers/readers.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -233,12 +233,11 @@ func listReaders(ctx context.Context, cmd *cli.Command) error {
233233
})
234234
}
235235

236-
return display.RenderTable(
237-
appCtx.Output,
238-
"Readers",
239-
[]string{"ID", "Name", "Status", "Model", "Identifier"},
240-
rows,
241-
)
236+
return display.RenderTableWithOptions(appCtx.Output, []string{"ID", "Name", "Status", "Model", "Identifier"}, rows, display.TableOptions{
237+
Title: "Readers",
238+
EmptyText: "No items to display",
239+
IdentifierColumns: []int{0},
240+
})
242241
}
243242

244243
func addReader(ctx context.Context, cmd *cli.Command) error {

internal/commands/transactions/transactions.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,12 +158,11 @@ func listTransactions(ctx context.Context, cmd *cli.Command) error {
158158
return display.PrintJSON(appCtx.Output, items)
159159
}
160160

161-
return display.RenderTable(
162-
appCtx.Output,
163-
"Transactions",
164-
[]string{"ID", "Code", "Amount", "Status", "Payment Type", "Created At"},
165-
transactionRows(appCtx, items),
166-
)
161+
return display.RenderTableWithOptions(appCtx.Output, []string{"ID", "Code", "Amount", "Status", "Payment Type", "Created At"}, transactionRows(appCtx, items), display.TableOptions{
162+
Title: "Transactions",
163+
EmptyText: "No items to display",
164+
IdentifierColumns: []int{0},
165+
})
167166
}
168167

169168
func getTransaction(ctx context.Context, cmd *cli.Command) error {

internal/display/output_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,22 @@ func TestRenderTableWithOptionsSupportsEmptyTextWithoutTitle(t *testing.T) {
9090
})
9191
}
9292

93+
func TestRenderTableWithOptions(t *testing.T) {
94+
t.Run("styles identifier columns explicitly instead of inferring from headers", func(t *testing.T) {
95+
var out bytes.Buffer
96+
97+
err := display.RenderTableWithOptions(&out, []string{"Token"}, [][]attribute.Value{
98+
{attribute.ValueOf("tok_123")},
99+
}, display.TableOptions{
100+
Title: "Tokens",
101+
IdentifierColumns: []int{0},
102+
})
103+
104+
require.NoError(t, err)
105+
assert.Equal(t, normalizeOutput("Tokens\nToken\ntok_123"), normalizeOutput(out.String()))
106+
})
107+
}
108+
93109
var ansiPattern = regexp.MustCompile(`\x1b\[[0-9;]*m`)
94110

95111
func normalizeOutput(value string) string {

internal/display/table.go

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,16 @@ const fallbackWidth = 120
1515

1616
// TableOptions customizes human-readable table rendering.
1717
type TableOptions struct {
18-
Title string
19-
EmptyText string
20-
HighlightIDColumns bool
18+
Title string
19+
EmptyText string
20+
IdentifierColumns []int
2121
}
2222

2323
// RenderTable prints rows in a table using the terminal width to wrap columns.
2424
func RenderTable(w io.Writer, title string, headers []string, rows [][]attribute.Value) error {
2525
return RenderTableWithOptions(w, headers, rows, TableOptions{
26-
Title: title,
27-
EmptyText: "No items to display",
28-
HighlightIDColumns: true,
26+
Title: title,
27+
EmptyText: "No items to display",
2928
})
3029
}
3130

@@ -49,12 +48,10 @@ func RenderTableWithOptions(w io.Writer, headers []string, rows [][]attribute.Va
4948
idStyle := basePadding.Foreground(SumUpPink).Bold(true)
5049
defaultStyle := basePadding
5150

52-
idColumns := make([]bool, len(headers))
53-
if opts.HighlightIDColumns {
54-
for i, header := range headers {
55-
if isIDHeader(header) {
56-
idColumns[i] = true
57-
}
51+
identifierColumns := make(map[int]struct{}, len(opts.IdentifierColumns))
52+
for _, idx := range opts.IdentifierColumns {
53+
if idx >= 0 && idx < len(headers) {
54+
identifierColumns[idx] = struct{}{}
5855
}
5956
}
6057

@@ -87,7 +84,7 @@ func RenderTableWithOptions(w io.Writer, headers []string, rows [][]attribute.Va
8784
if rowIndex := row - 1; rowIndex >= 0 && rowIndex < len(rows) && col >= 0 && col < len(rows[rowIndex]) {
8885
style = style.Inherit(rows[rowIndex][col].Style)
8986
}
90-
if col >= 0 && col < len(idColumns) && idColumns[col] {
87+
if _, ok := identifierColumns[col]; ok {
9188
style = style.Inherit(idStyle)
9289
}
9390
return style
@@ -104,7 +101,3 @@ func RenderTableWithOptions(w io.Writer, headers []string, rows [][]attribute.Va
104101
}
105102
return nil
106103
}
107-
108-
func isIDHeader(header string) bool {
109-
return strings.EqualFold(strings.TrimSpace(header), "id")
110-
}

0 commit comments

Comments
 (0)