Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e672906
Add endless-scrolling TUI table for interactive list commands
simonfaltum Mar 12, 2026
d7a7104
Fix stale fetch race condition and empty-table search restore
simonfaltum Mar 13, 2026
8b589d1
Merge branch 'main' into simonfaltum/list-tui-paginated
simonfaltum Mar 13, 2026
b7ca3d8
Add debounced live search to paginated TUI table
simonfaltum Mar 13, 2026
aa4cdb0
Fix search/fetch race conditions, esc restore, and error propagation
simonfaltum Mar 13, 2026
dbd2241
Fix lint: use assert.NoError per testifylint rule
simonfaltum Mar 13, 2026
831b105
Merge branch 'main' into simonfaltum/list-tui-paginated
simonfaltum Mar 14, 2026
229baa9
Fix UTF-8 backspace corruption and fragile typing check in search
simonfaltum Mar 16, 2026
78e6720
Fix RunPaginated silently dropping model-level fetch errors
simonfaltum Mar 16, 2026
78b56b7
Recompute column widths on every batch, not just the first
simonfaltum Mar 16, 2026
96e614a
Extract restorePreSearchState to fix DRY violation and stuck loading
simonfaltum Mar 16, 2026
3143a72
Show fetch errors in footer instead of replacing loaded data
simonfaltum Mar 16, 2026
a548b79
Fix sticky errors, missing space input, and search/fetch race in TUI …
simonfaltum Mar 16, 2026
43c526d
Fix search cancel silently dropping in-flight fetch rows
simonfaltum Mar 16, 2026
4281953
Fix search/fetch race: preserve loading state when no search was active
simonfaltum Mar 16, 2026
b3a6a53
Fix loading state stuck after canceling search without executing
simonfaltum Mar 16, 2026
7b4c0ee
Separate search and loading concerns in paginated model
simonfaltum Mar 16, 2026
aaf150e
Fix lint: remove extra blank line, convert if/else to switch
simonfaltum Mar 16, 2026
5709b10
Fix exhaustive lint: replace switch on tea.KeyType with if-else
simonfaltum Mar 17, 2026
ed23efc
Merge branch 'main' into simonfaltum/list-tui-paginated
simonfaltum Mar 18, 2026
c7fb162
Add curated TUI table overrides for list commands (#4731)
simonfaltum Mar 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/root/io.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ func (f *outputFlag) initializeIO(ctx context.Context, cmd *cobra.Command) (cont

cmdIO := cmdio.NewIO(ctx, f.output, cmd.InOrStdin(), cmd.OutOrStdout(), cmd.ErrOrStderr(), headerTemplate, template)
ctx = cmdio.InContext(ctx, cmdIO)
ctx = cmdio.WithCommand(ctx, cmd)
cmd.SetContext(ctx)
return ctx, nil
}
32 changes: 32 additions & 0 deletions cmd/workspace/alerts/overrides.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package alerts

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

func listOverride(listCmd *cobra.Command, listReq *sql.ListAlertsRequest) {
listCmd.Annotations["template"] = cmdio.Heredoc(`
{{range .}}{{green "%s" .Id}} {{.DisplayName}} {{.State}}
{{end}}`)

columns := []tableview.ColumnDef{
{Header: "ID", Extract: func(v any) string {
return v.(sql.ListAlertsResponseAlert).Id
}},
{Header: "Name", Extract: func(v any) string {
return v.(sql.ListAlertsResponseAlert).DisplayName
}},
{Header: "State", Extract: func(v any) string {
return string(v.(sql.ListAlertsResponseAlert).State)
}},
}

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

func init() {
listOverrides = append(listOverrides, listOverride)
}
28 changes: 28 additions & 0 deletions cmd/workspace/apps/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

appsCli "github.com/databricks/cli/cmd/apps"
"github.com/databricks/cli/libs/cmdio"
"github.com/databricks/cli/libs/tableview"
"github.com/databricks/databricks-sdk-go/service/apps"
"github.com/spf13/cobra"
)
Expand All @@ -15,6 +16,33 @@ func listOverride(listCmd *cobra.Command, listReq *apps.ListAppsRequest) {
listCmd.Annotations["template"] = cmdio.Heredoc(`
{{range .}}{{.Name | green}} {{.Url}} {{if .ComputeStatus}}{{if eq .ComputeStatus.State "ACTIVE"}}{{green "%s" .ComputeStatus.State }}{{else}}{{blue "%s" .ComputeStatus.State}}{{end}}{{end}} {{if .ActiveDeployment}}{{if eq .ActiveDeployment.Status.State "SUCCEEDED"}}{{green "%s" .ActiveDeployment.Status.State }}{{else}}{{blue "%s" .ActiveDeployment.Status.State}}{{end}}{{end}}
{{end}}`)

columns := []tableview.ColumnDef{
{Header: "Name", Extract: func(v any) string {
a := v.(apps.App)
return a.Name
}},
{Header: "URL", Extract: func(v any) string {
a := v.(apps.App)
return a.Url
}},
{Header: "Compute Status", Extract: func(v any) string {
a := v.(apps.App)
if a.ComputeStatus != nil {
return string(a.ComputeStatus.State)
}
return ""
}},
{Header: "Deploy Status", Extract: func(v any) string {
a := v.(apps.App)
if a.ActiveDeployment != nil && a.ActiveDeployment.Status != nil {
return string(a.ActiveDeployment.Status.State)
}
return ""
}},
}

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

func listDeploymentsOverride(listDeploymentsCmd *cobra.Command, listDeploymentsReq *apps.ListAppDeploymentsRequest) {
Expand Down
68 changes: 68 additions & 0 deletions cmd/workspace/apps/overrides_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package apps

import (
"testing"

"github.com/databricks/cli/libs/tableview"
sdkapps "github.com/databricks/databricks-sdk-go/service/apps"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestListTableConfig(t *testing.T) {
cmd := newList()

cfg := tableview.GetConfig(cmd)
require.NotNil(t, cfg)
require.Len(t, cfg.Columns, 4)

tests := []struct {
name string
app sdkapps.App
wantName string
wantURL string
wantCompute string
wantDeploy string
}{
{
name: "with nested fields",
app: sdkapps.App{
Name: "test-app",
Url: "https://example.com",
ComputeStatus: &sdkapps.ComputeStatus{
State: sdkapps.ComputeStateActive,
},
ActiveDeployment: &sdkapps.AppDeployment{
Status: &sdkapps.AppDeploymentStatus{
State: sdkapps.AppDeploymentStateSucceeded,
},
},
},
wantName: "test-app",
wantURL: "https://example.com",
wantCompute: "ACTIVE",
wantDeploy: "SUCCEEDED",
},
{
name: "nil nested fields",
app: sdkapps.App{
Name: "test-app",
Url: "https://example.com",
ActiveDeployment: &sdkapps.AppDeployment{},
},
wantName: "test-app",
wantURL: "https://example.com",
wantCompute: "",
wantDeploy: "",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.wantName, cfg.Columns[0].Extract(tt.app))
assert.Equal(t, tt.wantURL, cfg.Columns[1].Extract(tt.app))
assert.Equal(t, tt.wantCompute, cfg.Columns[2].Extract(tt.app))
assert.Equal(t, tt.wantDeploy, cfg.Columns[3].Extract(tt.app))
})
}
}
15 changes: 15 additions & 0 deletions cmd/workspace/catalogs/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package catalogs

import (
"github.com/databricks/cli/libs/cmdio"
"github.com/databricks/cli/libs/tableview"
"github.com/databricks/databricks-sdk-go/service/catalog"
"github.com/spf13/cobra"
)
Expand All @@ -12,6 +13,20 @@ func listOverride(listCmd *cobra.Command, listReq *catalog.ListCatalogsRequest)
listCmd.Annotations["template"] = cmdio.Heredoc(`
{{range .}}{{.Name|green}} {{blue "%s" .CatalogType}} {{.Comment}}
{{end}}`)

columns := []tableview.ColumnDef{
{Header: "Name", Extract: func(v any) string {
return v.(catalog.CatalogInfo).Name
}},
{Header: "Type", Extract: func(v any) string {
return string(v.(catalog.CatalogInfo).CatalogType)
}},
{Header: "Comment", MaxWidth: 40, Extract: func(v any) string {
return v.(catalog.CatalogInfo).Comment
}},
}

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

func init() {
Expand Down
15 changes: 15 additions & 0 deletions cmd/workspace/clusters/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"strings"

"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 @@ -17,6 +18,20 @@ func listOverride(listCmd *cobra.Command, listReq *compute.ListClustersRequest)
{{range .}}{{.ClusterId | green}} {{.ClusterName | cyan}} {{if eq .State "RUNNING"}}{{green "%s" .State}}{{else if eq .State "TERMINATED"}}{{red "%s" .State}}{{else}}{{blue "%s" .State}}{{end}}
{{end}}`)

columns := []tableview.ColumnDef{
{Header: "Cluster ID", Extract: func(v any) string {
return v.(compute.ClusterDetails).ClusterId
}},
{Header: "Name", Extract: func(v any) string {
return v.(compute.ClusterDetails).ClusterName
}},
{Header: "State", Extract: func(v any) string {
return string(v.(compute.ClusterDetails).State)
}},
}

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

listReq.FilterBy = &compute.ListClustersFilterBy{}
listCmd.Flags().BoolVar(&listReq.FilterBy.IsPinned, "is-pinned", false, "Filter clusters by pinned status")
listCmd.Flags().StringVar(&listReq.FilterBy.PolicyId, "policy-id", "", "Filter clusters by policy id")
Expand Down
15 changes: 15 additions & 0 deletions cmd/workspace/external-locations/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package external_locations

import (
"github.com/databricks/cli/libs/cmdio"
"github.com/databricks/cli/libs/tableview"
"github.com/databricks/databricks-sdk-go/service/catalog"
"github.com/spf13/cobra"
)
Expand All @@ -12,6 +13,20 @@ func listOverride(listCmd *cobra.Command, listReq *catalog.ListExternalLocations
listCmd.Annotations["template"] = cmdio.Heredoc(`
{{range .}}{{.Name|green}} {{.CredentialName|cyan}} {{.Url}}
{{end}}`)

columns := []tableview.ColumnDef{
{Header: "Name", Extract: func(v any) string {
return v.(catalog.ExternalLocationInfo).Name
}},
{Header: "Credential", Extract: func(v any) string {
return v.(catalog.ExternalLocationInfo).CredentialName
}},
{Header: "URL", Extract: func(v any) string {
return v.(catalog.ExternalLocationInfo).Url
}},
}

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

func init() {
Expand Down
19 changes: 19 additions & 0 deletions cmd/workspace/instance-pools/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,32 @@ package instance_pools

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"
)

func listOverride(listCmd *cobra.Command) {
listCmd.Annotations["template"] = cmdio.Heredoc(`
{{range .}}{{.InstancePoolId|green}} {{.InstancePoolName}} {{.NodeTypeId}} {{.State}}
{{end}}`)

columns := []tableview.ColumnDef{
{Header: "Pool ID", Extract: func(v any) string {
return v.(compute.InstancePoolAndStats).InstancePoolId
}},
{Header: "Name", Extract: func(v any) string {
return v.(compute.InstancePoolAndStats).InstancePoolName
}},
{Header: "Node Type", Extract: func(v any) string {
return v.(compute.InstancePoolAndStats).NodeTypeId
}},
{Header: "State", Extract: func(v any) string {
return string(v.(compute.InstancePoolAndStats).State)
}},
}

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

func init() {
Expand Down
32 changes: 32 additions & 0 deletions cmd/workspace/jobs/overrides.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package jobs

import (
"context"
"strconv"

"github.com/databricks/cli/libs/cmdctx"
"github.com/databricks/cli/libs/cmdio"
"github.com/databricks/cli/libs/tableview"
"github.com/databricks/databricks-sdk-go/service/jobs"
"github.com/spf13/cobra"
)
Expand All @@ -10,6 +15,33 @@ func listOverride(listCmd *cobra.Command, listReq *jobs.ListJobsRequest) {
listCmd.Annotations["template"] = cmdio.Heredoc(`
{{range .}}{{green "%d" .JobId}} {{.Settings.Name}}
{{end}}`)

columns := []tableview.ColumnDef{
{Header: "Job ID", Extract: func(v any) string {
return strconv.FormatInt(v.(jobs.BaseJob).JobId, 10)
}},
{Header: "Name", Extract: func(v any) string {
if v.(jobs.BaseJob).Settings != nil {
return v.(jobs.BaseJob).Settings.Name
}
return ""
}},
}

tableview.RegisterConfig(listCmd, tableview.TableConfig{
Columns: columns,
Search: &tableview.SearchConfig{
Placeholder: "Search by exact name...",
NewIterator: func(ctx context.Context, query string) tableview.RowIterator {
req := *listReq
req.Name = query
req.PageToken = ""
req.Offset = 0
w := cmdctx.WorkspaceClient(ctx)
return tableview.WrapIterator(w.Jobs.List(ctx, req), columns)
},
},
})
}

func listRunsOverride(listRunsCmd *cobra.Command, listRunsReq *jobs.ListRunsRequest) {
Expand Down
50 changes: 50 additions & 0 deletions cmd/workspace/jobs/overrides_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package jobs

import (
"testing"

"github.com/databricks/cli/libs/tableview"
sdkjobs "github.com/databricks/databricks-sdk-go/service/jobs"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestListTableConfig(t *testing.T) {
cmd := newList()

cfg := tableview.GetConfig(cmd)
require.NotNil(t, cfg)
require.Len(t, cfg.Columns, 2)

tests := []struct {
name string
job sdkjobs.BaseJob
wantID string
wantName string
}{
{
name: "with settings",
job: sdkjobs.BaseJob{
JobId: 123,
Settings: &sdkjobs.JobSettings{Name: "test-job"},
},
wantID: "123",
wantName: "test-job",
},
{
name: "nil settings",
job: sdkjobs.BaseJob{
JobId: 456,
},
wantID: "456",
wantName: "",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.wantID, cfg.Columns[0].Extract(tt.job))
assert.Equal(t, tt.wantName, cfg.Columns[1].Extract(tt.job))
})
}
}
Loading
Loading