Skip to content
2 changes: 1 addition & 1 deletion cmd/workspace/alerts/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/spf13/cobra"
)

func listOverride(listCmd *cobra.Command, listReq *sql.ListAlertsRequest) {
func listOverride(listCmd *cobra.Command, _ *sql.ListAlertsRequest) {
listCmd.Annotations["template"] = cmdio.Heredoc(`
{{range .}}{{green "%s" .Id}} {{.DisplayName}} {{.State}}
{{end}}`)
Expand Down
4 changes: 2 additions & 2 deletions cmd/workspace/apps/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/spf13/cobra"
)

func listOverride(listCmd *cobra.Command, listReq *apps.ListAppsRequest) {
func listOverride(listCmd *cobra.Command, _ *apps.ListAppsRequest) {
listCmd.Annotations["headerTemplate"] = cmdio.Heredoc(`
{{header "Name"}} {{header "Url"}} {{header "ComputeStatus"}} {{header "DeploymentStatus"}}`)
listCmd.Annotations["template"] = cmdio.Heredoc(`
Expand Down Expand Up @@ -41,7 +41,7 @@ func listOverride(listCmd *cobra.Command, listReq *apps.ListAppsRequest) {
tableview.RegisterConfig(listCmd, tableview.TableConfig{Columns: columns})
}

func listDeploymentsOverride(listDeploymentsCmd *cobra.Command, listDeploymentsReq *apps.ListAppDeploymentsRequest) {
func listDeploymentsOverride(listDeploymentsCmd *cobra.Command, _ *apps.ListAppDeploymentsRequest) {
listDeploymentsCmd.Annotations["headerTemplate"] = cmdio.Heredoc(`
{{header "DeploymentId"}} {{header "State"}} {{header "CreatedAt"}}`)
listDeploymentsCmd.Annotations["template"] = cmdio.Heredoc(`
Expand Down
2 changes: 1 addition & 1 deletion cmd/workspace/catalogs/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/spf13/cobra"
)

func listOverride(listCmd *cobra.Command, listReq *catalog.ListCatalogsRequest) {
func listOverride(listCmd *cobra.Command, _ *catalog.ListCatalogsRequest) {
listCmd.Annotations["headerTemplate"] = cmdio.Heredoc(`
{{header "Name"}} {{header "Type"}} {{header "Comment"}}`)
listCmd.Annotations["template"] = cmdio.Heredoc(`
Expand Down
18 changes: 18 additions & 0 deletions cmd/workspace/cluster-policies/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cluster_policies

import (
"github.com/databricks/cli/libs/cmdio"
"github.com/databricks/cli/libs/tableview"
"github.com/databricks/databricks-sdk-go/service/compute"
"github.com/spf13/cobra"
)
Expand All @@ -10,6 +11,23 @@ func listOverride(listCmd *cobra.Command, _ *compute.ListClusterPoliciesRequest)
listCmd.Annotations["template"] = cmdio.Heredoc(`
{{range .}}{{.PolicyId | green}} {{.Name}}
{{end}}`)

columns := []tableview.ColumnDef{
{Header: "Policy ID", Extract: func(v any) string {
return v.(compute.Policy).PolicyId
}},
{Header: "Name", Extract: func(v any) string {
return v.(compute.Policy).Name
}},
{Header: "Default", Extract: func(v any) string {
if v.(compute.Policy).IsDefault {
return "yes"
}
return ""
}},
}

tableview.RegisterConfig(listCmd, tableview.TableConfig{Columns: columns})
}

func getOverride(getCmd *cobra.Command, _ *compute.GetClusterPolicyRequest) {
Expand Down
2 changes: 1 addition & 1 deletion cmd/workspace/external-locations/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/spf13/cobra"
)

func listOverride(listCmd *cobra.Command, listReq *catalog.ListExternalLocationsRequest) {
func listOverride(listCmd *cobra.Command, _ *catalog.ListExternalLocationsRequest) {
listCmd.Annotations["headerTemplate"] = cmdio.Heredoc(`
{{header "Name"}} {{header "Credential"}} {{header "URL"}}`)
listCmd.Annotations["template"] = cmdio.Heredoc(`
Expand Down
2 changes: 1 addition & 1 deletion cmd/workspace/jobs/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func listOverride(listCmd *cobra.Command, listReq *jobs.ListJobsRequest) {
})
}

func listRunsOverride(listRunsCmd *cobra.Command, listRunsReq *jobs.ListRunsRequest) {
func listRunsOverride(listRunsCmd *cobra.Command, _ *jobs.ListRunsRequest) {
listRunsCmd.Annotations["headerTemplate"] = cmdio.Heredoc(`
{{header "Job ID"}} {{header "Run ID"}} {{header "Result State"}} URL`)
listRunsCmd.Annotations["template"] = cmdio.Heredoc(`
Expand Down
25 changes: 25 additions & 0 deletions cmd/workspace/lakeview/overrides.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
package lakeview

import (
"github.com/databricks/cli/libs/cmdio"
"github.com/databricks/cli/libs/tableview"
"github.com/databricks/databricks-sdk-go/service/dashboards"
"github.com/spf13/cobra"
)

func listOverride(listCmd *cobra.Command, _ *dashboards.ListDashboardsRequest) {
listCmd.Annotations["headerTemplate"] = cmdio.Heredoc(`
{{header "Dashboard ID"}} {{header "Name"}} {{header "State"}}`)
listCmd.Annotations["template"] = cmdio.Heredoc(`
{{range .}}{{green "%s" .DashboardId}} {{.DisplayName}} {{blue "%s" .LifecycleState}}
{{end}}`)

columns := []tableview.ColumnDef{
{Header: "Dashboard ID", Extract: func(v any) string {
return v.(dashboards.Dashboard).DashboardId
}},
{Header: "Name", Extract: func(v any) string {
return v.(dashboards.Dashboard).DisplayName
}},
{Header: "State", Extract: func(v any) string {
return string(v.(dashboards.Dashboard).LifecycleState)
}},
}

tableview.RegisterConfig(listCmd, tableview.TableConfig{Columns: columns})
}

func publishOverride(cmd *cobra.Command, req *dashboards.PublishRequest) {
originalRunE := cmd.RunE
cmd.RunE = func(cmd *cobra.Command, args []string) error {
Expand All @@ -15,5 +39,6 @@ func publishOverride(cmd *cobra.Command, req *dashboards.PublishRequest) {
}

func init() {
listOverrides = append(listOverrides, listOverride)
publishOverrides = append(publishOverrides, publishOverride)
}
34 changes: 34 additions & 0 deletions cmd/workspace/pipelines/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,34 @@ func listPipelinesOverride(listCmd *cobra.Command, listReq *pipelines.ListPipeli
})
}

func listPipelineEventsOverride(listCmd *cobra.Command, _ *pipelines.ListPipelineEventsRequest) {
listCmd.Annotations["headerTemplate"] = cmdio.Heredoc(`
{{header "Timestamp"}} {{header "Level"}} {{header "Event Type"}} {{header "Message"}}`)
listCmd.Annotations["template"] = cmdio.Heredoc(`
{{range .}}{{.Timestamp}} {{.Level}} {{.EventType}} {{.Message | sanitize}}
{{end}}`)

columns := []tableview.ColumnDef{
{Header: "Timestamp", Extract: func(v any) string {
return v.(pipelines.PipelineEvent).Timestamp
}},
{Header: "Level", Extract: func(v any) string {
return string(v.(pipelines.PipelineEvent).Level)
}},
{Header: "Event Type", Extract: func(v any) string {
return v.(pipelines.PipelineEvent).EventType
}},
{Header: "Message", MaxWidth: 200, Extract: func(v any) string {
return sanitizeWhitespace(v.(pipelines.PipelineEvent).Message)
}},
}

tableview.RegisterConfig(listCmd, tableview.TableConfig{Columns: columns})
}

func init() {
listPipelinesOverrides = append(listPipelinesOverrides, listPipelinesOverride)
listPipelineEventsOverrides = append(listPipelineEventsOverrides, listPipelineEventsOverride)

cmdOverrides = append(cmdOverrides, func(cli *cobra.Command) {
// all auto-generated commands apart from nonManagementCommands go into 'management' group
Expand Down Expand Up @@ -118,6 +144,14 @@ With a PIPELINE_ID: Stops the pipeline identified by the UUID using the API.`
})
}

var controlWhitespaceReplacer = strings.NewReplacer("\n", " ", "\r", " ", "\t", " ")

// sanitizeWhitespace replaces control whitespace (newlines, tabs) with spaces
// to prevent corrupting tab-delimited or TUI table output.
func sanitizeWhitespace(s string) string {
return controlWhitespaceReplacer.Replace(s)
}

var uuidRegex = regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`)

// looksLikeUUID checks if a string matches the UUID format with lowercase hex digits
Expand Down
2 changes: 1 addition & 1 deletion cmd/workspace/repos/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
"github.com/spf13/cobra"
)

func listOverride(listCmd *cobra.Command, listReq *workspace.ListReposRequest) {
func listOverride(listCmd *cobra.Command, _ *workspace.ListReposRequest) {
listCmd.Annotations["template"] = cmdio.Heredoc(`
{{range .}}{{green "%d" .Id}} {{.Path}} {{.Branch|blue}} {{.Url|cyan}}
{{end}}`)
Expand Down
2 changes: 1 addition & 1 deletion cmd/workspace/schemas/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/spf13/cobra"
)

func listOverride(listCmd *cobra.Command, listReq *catalog.ListSchemasRequest) {
func listOverride(listCmd *cobra.Command, _ *catalog.ListSchemasRequest) {
listCmd.Annotations["headerTemplate"] = cmdio.Heredoc(`
{{header "Full Name"}} {{header "Owner"}} {{header "Comment"}}`)
listCmd.Annotations["template"] = cmdio.Heredoc(`
Expand Down
29 changes: 29 additions & 0 deletions cmd/workspace/secrets/overrides.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package secrets

import (
"time"

"github.com/databricks/cli/libs/cmdio"
"github.com/databricks/cli/libs/tableview"
"github.com/databricks/databricks-sdk-go/service/workspace"
"github.com/spf13/cobra"
)
Expand All @@ -16,6 +19,17 @@ func listScopesOverride(listScopesCmd *cobra.Command) {
listScopesCmd.Annotations["template"] = cmdio.Heredoc(`
{{range .}}{{.Name|green}} {{.BackendType}}
{{end}}`)

columns := []tableview.ColumnDef{
{Header: "Scope", Extract: func(v any) string {
return v.(workspace.SecretScope).Name
}},
{Header: "Backend Type", Extract: func(v any) string {
return string(v.(workspace.SecretScope).BackendType)
}},
}

tableview.RegisterConfig(listScopesCmd, tableview.TableConfig{Columns: columns})
}

func listSecretsOverride(listSecretsCommand *cobra.Command, _ *workspace.ListSecretsRequest) {
Expand All @@ -24,6 +38,21 @@ func listSecretsOverride(listSecretsCommand *cobra.Command, _ *workspace.ListSec
listSecretsCommand.Annotations["template"] = cmdio.Heredoc(`
{{range .}}{{.Key|green}} {{.LastUpdatedTimestamp}}
{{end}}`)

columns := []tableview.ColumnDef{
{Header: "Key", Extract: func(v any) string {
return v.(workspace.SecretMetadata).Key
}},
{Header: "Last Updated", Extract: func(v any) string {
ts := v.(workspace.SecretMetadata).LastUpdatedTimestamp
if ts == 0 {
return ""
}
return time.UnixMilli(ts).UTC().Format("2006-01-02 15:04:05")
}},
}

tableview.RegisterConfig(listSecretsCommand, tableview.TableConfig{Columns: columns})
}

func init() {
Expand Down
2 changes: 1 addition & 1 deletion cmd/workspace/tables/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/spf13/cobra"
)

func listOverride(listCmd *cobra.Command, listReq *catalog.ListTablesRequest) {
func listOverride(listCmd *cobra.Command, _ *catalog.ListTablesRequest) {
listCmd.Annotations["headerTemplate"] = cmdio.Heredoc(`
{{header "Full Name"}} {{header "Table Type"}}`)
listCmd.Annotations["template"] = cmdio.Heredoc(`
Expand Down
2 changes: 1 addition & 1 deletion cmd/workspace/volumes/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/spf13/cobra"
)

func listOverride(listCmd *cobra.Command, listReq *catalog.ListVolumesRequest) {
func listOverride(listCmd *cobra.Command, _ *catalog.ListVolumesRequest) {
listCmd.Annotations["template"] = cmdio.Heredoc(`
{{range .}}{{green "%s" .Name}} {{.VolumeType}} {{.FullName}}
{{end}}`)
Expand Down
2 changes: 1 addition & 1 deletion cmd/workspace/warehouses/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/spf13/cobra"
)

func listOverride(listCmd *cobra.Command, listReq *sql.ListWarehousesRequest) {
func listOverride(listCmd *cobra.Command, _ *sql.ListWarehousesRequest) {
listCmd.Annotations["headerTemplate"] = cmdio.Heredoc(`
{{header "ID"}} {{header "Name"}} {{header "Size"}} {{header "State"}}`)
listCmd.Annotations["template"] = cmdio.Heredoc(`
Expand Down
11 changes: 10 additions & 1 deletion libs/cmdio/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,14 @@ func RenderIteratorJson[T any](ctx context.Context, i listing.Iterator[T]) error
return renderWithTemplate(ctx, newIteratorRenderer(i), c.outputFormat, c.out, c.headerTemplate, c.template)
}

var controlWhitespaceReplacer = strings.NewReplacer("\n", " ", "\r", " ", "\t", " ")

// sanitizeControlWhitespace replaces newlines and tabs with spaces to prevent
// corrupting tab-delimited text output.
func sanitizeControlWhitespace(s string) string {
return controlWhitespaceReplacer.Replace(s)
}

var renderFuncMap = template.FuncMap{
// we render colored output if stdout is TTY, otherwise we render text.
// in the future we'll check if we can explicitly check for stderr being
Expand All @@ -330,7 +338,8 @@ var renderFuncMap = template.FuncMap{
"italic": func(format string, a ...any) string {
return color.New(color.Italic).Sprintf(format, a...)
},
"replace": strings.ReplaceAll,
"replace": strings.ReplaceAll,
"sanitize": sanitizeControlWhitespace,
"join": strings.Join,
"sub": func(a, b int) int {
return a - b
Expand Down
7 changes: 5 additions & 2 deletions libs/tableview/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import "context"

// ColumnDef defines a column in the TUI table.
type ColumnDef struct {
Header string // Display name in header row.
MaxWidth int // Max cell width; 0 = default (50).
Header string // Display name in header row.
// MaxWidth caps cell display width; 0 = default (50). Values exceeding
// this limit are destructively truncated with "..." in the rendered
// output. Horizontal scrolling does not recover the hidden portion.
MaxWidth int
Extract func(v any) string // Extracts cell value from typed SDK struct.
}

Expand Down
25 changes: 17 additions & 8 deletions libs/tableview/paginated.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ type paginatedModel struct {
limitReached bool
}

// Err returns the error recorded during data fetching, if any.
func (m paginatedModel) Err() error {
return m.err
}

// newFetchCmdFunc returns a closure that creates fetch commands, capturing ctx.
func newFetchCmdFunc(ctx context.Context) func(paginatedModel) tea.Cmd {
return func(m paginatedModel) tea.Cmd {
Expand Down Expand Up @@ -151,13 +156,16 @@ func NewPaginatedProgram(ctx context.Context, w io.Writer, cfg *TableConfig, ite
// RunPaginated launches the paginated TUI table.
func RunPaginated(ctx context.Context, w io.Writer, cfg *TableConfig, iter RowIterator, maxItems int) error {
p := NewPaginatedProgram(ctx, w, cfg, iter, maxItems)
_, err := p.Run()
return err
}

// Err returns any error that occurred during data fetching.
func (m paginatedModel) Err() error {
return m.err
finalModel, err := p.Run()
if err != nil {
return err
}
if m, ok := finalModel.(FinalModel); ok {
if fetchErr := m.Err(); fetchErr != nil {
return fetchErr
}
}
return nil
}

func (m paginatedModel) Init() tea.Cmd {
Expand Down Expand Up @@ -263,7 +271,8 @@ func (m paginatedModel) renderContent() string {
}
fmt.Fprintln(tw, strings.Join(seps, "\t"))

// Data rows
// Data rows.
// MaxWidth truncation is destructive; horizontal scroll won't recover hidden text.
for _, row := range m.rows {
vals := make([]string, len(m.headers))
for i := range m.headers {
Expand Down