refactor: NewTable for consistent CLI table rendering, style images for ls,ps

This commit is contained in:
Pasha Sviderski
2026-03-30 14:08:50 +10:00
parent 9aee75ba28
commit e22cdf0b18
6 changed files with 35 additions and 41 deletions
+2 -2
View File
@@ -88,12 +88,12 @@ func runDeploy(ctx context.Context, uncli *cli.CLI, opts deployOptions) error {
if len(currentImages) > 1 { if len(currentImages) > 1 {
formattedImages := make([]string, len(currentImages)) formattedImages := make([]string, len(currentImages))
for i, img := range currentImages { for i, img := range currentImages {
formattedImages[i] = tui.FormatImage(img, lipgloss.NewStyle()) formattedImages[i] = tui.FormatImage(img, tui.NoStyle)
} }
fmt.Println(tui.Faint.Render("current images (multiple versions detected): ") + fmt.Println(tui.Faint.Render("current images (multiple versions detected): ") +
strings.Join(formattedImages, tui.Faint.Render(", "))) strings.Join(formattedImages, tui.Faint.Render(", ")))
} else { } else {
fmt.Println(tui.Faint.Render("current image: ") + tui.FormatImage(currentImages[0], lipgloss.NewStyle())) fmt.Println(tui.Faint.Render("current image: ") + tui.FormatImage(currentImages[0], tui.NoStyle))
} }
} }
+3 -18
View File
@@ -10,13 +10,13 @@ import (
"time" "time"
"charm.land/lipgloss/v2" "charm.land/lipgloss/v2"
"charm.land/lipgloss/v2/table"
"github.com/charmbracelet/colorprofile" "github.com/charmbracelet/colorprofile"
"github.com/containerd/platforms" "github.com/containerd/platforms"
"github.com/docker/docker/api/types/image" "github.com/docker/docker/api/types/image"
"github.com/docker/go-units" "github.com/docker/go-units"
"github.com/psviderski/uncloud/internal/cli" "github.com/psviderski/uncloud/internal/cli"
"github.com/psviderski/uncloud/internal/cli/tui"
"github.com/psviderski/uncloud/pkg/api" "github.com/psviderski/uncloud/pkg/api"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@@ -260,22 +260,7 @@ func formatImageTable(rows []imageRow) string {
columns[5].hide = true columns[5].hide = true
} }
t := table.New(). t := tui.NewTable()
// Remove the default border.
Border(lipgloss.Border{}).
BorderTop(false).
BorderBottom(false).
BorderLeft(false).
BorderRight(false).
BorderHeader(false).
BorderColumn(false).
StyleFunc(func(row, col int) lipgloss.Style {
if row == table.HeaderRow {
return lipgloss.NewStyle().Bold(true).PaddingRight(3)
}
// Regular style for data rows with padding.
return lipgloss.NewStyle().PaddingRight(3)
})
var headers []string var headers []string
for _, col := range columns { for _, col := range columns {
@@ -288,7 +273,7 @@ func formatImageTable(rows []imageRow) string {
for _, row := range rows { for _, row := range rows {
values := []string{ values := []string{
row.id, row.id,
row.name, tui.FormatImage(row.name, tui.NoStyle),
row.platforms, row.platforms,
row.createdHuman, row.createdHuman,
row.size, row.size,
+2 -19
View File
@@ -8,7 +8,6 @@ import (
"charm.land/huh/v2/spinner" "charm.land/huh/v2/spinner"
"charm.land/lipgloss/v2" "charm.land/lipgloss/v2"
"charm.land/lipgloss/v2/table"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/docker/go-units" "github.com/docker/go-units"
"github.com/psviderski/uncloud/internal/cli/tui" "github.com/psviderski/uncloud/internal/cli/tui"
@@ -132,23 +131,7 @@ func runPs(ctx context.Context, uncli *cli.CLI, opts psOptions) error {
} }
func printContainers(containers []containerInfo) error { func printContainers(containers []containerInfo) error {
t := table.New(). t := tui.NewTable()
// Remove the default border.
Border(lipgloss.Border{}).
BorderTop(false).
BorderBottom(false).
BorderLeft(false).
BorderRight(false).
BorderHeader(false).
BorderColumn(false).
StyleFunc(func(row, col int) lipgloss.Style {
if row == table.HeaderRow {
return lipgloss.NewStyle().Bold(true).PaddingRight(3)
}
// Regular style for data rows with padding.
return lipgloss.NewStyle().PaddingRight(3)
})
t.Headers("SERVICE", "CONTAINER ID", "CONTAINER NAME", "IMAGE", "CREATED", "STATUS", "IP ADDRESS", "MACHINE") t.Headers("SERVICE", "CONTAINER ID", "CONTAINER NAME", "IMAGE", "CREATED", "STATUS", "IP ADDRESS", "MACHINE")
for _, ctr := range containers { for _, ctr := range containers {
@@ -175,7 +158,7 @@ func printContainers(containers []containerInfo) error {
ctr.serviceName, ctr.serviceName,
id, id,
ctr.name, ctr.name,
ctr.image, tui.FormatImage(ctr.image, tui.NoStyle),
created, created,
statusStyle.Render(ctr.status), statusStyle.Render(ctr.status),
ctr.ip, ctr.ip,
+2
View File
@@ -6,6 +6,8 @@ import (
) )
var ( var (
NoStyle = lipgloss.NewStyle()
Faint = lipgloss.NewStyle().Faint(true) Faint = lipgloss.NewStyle().Faint(true)
Red = lipgloss.NewStyle().Foreground(lipgloss.Red) Red = lipgloss.NewStyle().Foreground(lipgloss.Red)
Green = lipgloss.NewStyle().Foreground(lipgloss.Green) Green = lipgloss.NewStyle().Foreground(lipgloss.Green)
+24
View File
@@ -0,0 +1,24 @@
package tui
import (
"charm.land/lipgloss/v2"
"charm.land/lipgloss/v2/table"
)
// NewTable creates a borderless table with bold headers and consistent padding for CLI output.
func NewTable() *table.Table {
return table.New().
Border(lipgloss.Border{}).
BorderTop(false).
BorderBottom(false).
BorderLeft(false).
BorderRight(false).
BorderHeader(false).
BorderColumn(false).
StyleFunc(func(row, col int) lipgloss.Style {
if row == table.HeaderRow {
return Bold.PaddingRight(3)
}
return NoStyle.PaddingRight(3)
})
}
+2 -2
View File
@@ -114,7 +114,7 @@ func (sp *ServicePlan) Format() string {
if sp.IsNewService { if sp.IsNewService {
specTable.Row("", "image:", tui.FormatImage(sp.Spec.Container.Image, tui.Green)) specTable.Row("", "image:", tui.FormatImage(sp.Spec.Container.Image, tui.Green))
} else { } else {
specTable.Row("", "image:", tui.FormatImage(sp.Spec.Container.Image, lipgloss.NewStyle())) specTable.Row("", "image:", tui.FormatImage(sp.Spec.Container.Image, tui.NoStyle))
} }
} else { } else {
mod := "" mod := ""
@@ -233,7 +233,7 @@ func formatImageDiff(oldImage, newImage string) string {
} }
if oldImage == newImage { if oldImage == newImage {
return tui.FormatImage(newImage, lipgloss.NewStyle()) return tui.FormatImage(newImage, tui.NoStyle)
} }
oldRef, _ := reference.ParseDockerRef(oldImage) oldRef, _ := reference.ParseDockerRef(oldImage)