diff --git a/cmd/workspace/alerts/overrides.go b/cmd/workspace/alerts/overrides.go new file mode 100644 index 0000000000..ed5fdaa8db --- /dev/null +++ b/cmd/workspace/alerts/overrides.go @@ -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) +} diff --git a/cmd/workspace/apps/overrides.go b/cmd/workspace/apps/overrides.go index 6a909a943e..ec6a25b803 100644 --- a/cmd/workspace/apps/overrides.go +++ b/cmd/workspace/apps/overrides.go @@ -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" ) @@ -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) { diff --git a/cmd/workspace/apps/overrides_test.go b/cmd/workspace/apps/overrides_test.go new file mode 100644 index 0000000000..c2d374f38b --- /dev/null +++ b/cmd/workspace/apps/overrides_test.go @@ -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)) + }) + } +} diff --git a/cmd/workspace/catalogs/overrides.go b/cmd/workspace/catalogs/overrides.go index e2201dc152..46d66a08b2 100644 --- a/cmd/workspace/catalogs/overrides.go +++ b/cmd/workspace/catalogs/overrides.go @@ -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" ) @@ -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() { diff --git a/cmd/workspace/clusters/overrides.go b/cmd/workspace/clusters/overrides.go index 6038978ae4..910918b017 100644 --- a/cmd/workspace/clusters/overrides.go +++ b/cmd/workspace/clusters/overrides.go @@ -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" ) @@ -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") diff --git a/cmd/workspace/external-locations/overrides.go b/cmd/workspace/external-locations/overrides.go index 00b4921d4d..9d9108f5be 100644 --- a/cmd/workspace/external-locations/overrides.go +++ b/cmd/workspace/external-locations/overrides.go @@ -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" ) @@ -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() { diff --git a/cmd/workspace/instance-pools/overrides.go b/cmd/workspace/instance-pools/overrides.go index f62f8c5367..ddf6181f15 100644 --- a/cmd/workspace/instance-pools/overrides.go +++ b/cmd/workspace/instance-pools/overrides.go @@ -2,6 +2,8 @@ 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" ) @@ -9,6 +11,23 @@ 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() { diff --git a/cmd/workspace/jobs/overrides.go b/cmd/workspace/jobs/overrides.go index ee7d205517..d9786601ba 100644 --- a/cmd/workspace/jobs/overrides.go +++ b/cmd/workspace/jobs/overrides.go @@ -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" ) @@ -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) { diff --git a/cmd/workspace/jobs/overrides_test.go b/cmd/workspace/jobs/overrides_test.go new file mode 100644 index 0000000000..66bcb5da27 --- /dev/null +++ b/cmd/workspace/jobs/overrides_test.go @@ -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)) + }) + } +} diff --git a/cmd/workspace/pipelines/overrides.go b/cmd/workspace/pipelines/overrides.go index 08c36deabe..361c834bfa 100644 --- a/cmd/workspace/pipelines/overrides.go +++ b/cmd/workspace/pipelines/overrides.go @@ -1,15 +1,70 @@ package pipelines import ( + "context" + "fmt" "regexp" "slices" + "strings" pipelinesCli "github.com/databricks/cli/cmd/pipelines" + "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/pipelines" "github.com/spf13/cobra" ) +func listPipelinesOverride(listCmd *cobra.Command, listReq *pipelines.ListPipelinesRequest) { + listCmd.Annotations["template"] = cmdio.Heredoc(` + {{range .}}{{green "%s" .PipelineId}} {{.Name}} {{blue "%s" .State}} + {{end}}`) + + columns := []tableview.ColumnDef{ + {Header: "Pipeline ID", Extract: func(v any) string { + return v.(pipelines.PipelineStateInfo).PipelineId + }}, + {Header: "Name", Extract: func(v any) string { + return v.(pipelines.PipelineStateInfo).Name + }}, + {Header: "State", Extract: func(v any) string { + return string(v.(pipelines.PipelineStateInfo).State) + }}, + } + + tableview.RegisterConfig(listCmd, tableview.TableConfig{ + Columns: columns, + Search: &tableview.SearchConfig{ + Placeholder: "Filter by name...", + NewIterator: func(ctx context.Context, query string) tableview.RowIterator { + req := *listReq + req.PageToken = "" + escaped := strings.ReplaceAll(query, `\`, `\\`) + escaped = strings.ReplaceAll(escaped, "'", "''") + escaped = strings.ReplaceAll(escaped, "%", `\%`) + escaped = strings.ReplaceAll(escaped, "_", `\_`) + req.Filter = fmt.Sprintf("name LIKE '%%%s%%'", escaped) + w := cmdctx.WorkspaceClient(ctx) + return tableview.WrapIterator(w.Pipelines.ListPipelines(ctx, req), columns) + }, + }, + }) + + // The pipelines API does not support composite filters, so disable + // TUI search when the user passes --filter on the command line. + origPreRunE := listCmd.PreRunE + listCmd.PreRunE = func(cmd *cobra.Command, args []string) error { + disableSearchIfFilterSet(cmd) + if origPreRunE != nil { + return origPreRunE(cmd, args) + } + return nil + } +} + func init() { + listPipelinesOverrides = append(listPipelinesOverrides, listPipelinesOverride) + cmdOverrides = append(cmdOverrides, func(cli *cobra.Command) { // all auto-generated commands apart from nonManagementCommands go into 'management' group nonManagementCommands := []string{ @@ -71,6 +126,15 @@ With a PIPELINE_ID: Stops the pipeline identified by the UUID using the API.` }) } +// disableSearchIfFilterSet clears the TUI search config when --filter is active. +func disableSearchIfFilterSet(cmd *cobra.Command) { + if cmd.Flags().Changed("filter") { + if cfg := tableview.GetConfig(cmd); cfg != nil { + cfg.Search = nil + } + } +} + 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 diff --git a/cmd/workspace/pipelines/overrides_test.go b/cmd/workspace/pipelines/overrides_test.go index 2e70cf4845..27f3c26588 100644 --- a/cmd/workspace/pipelines/overrides_test.go +++ b/cmd/workspace/pipelines/overrides_test.go @@ -3,7 +3,13 @@ package pipelines import ( "testing" + "github.com/databricks/cli/libs/cmdctx" + "github.com/databricks/cli/libs/tableview" + "github.com/databricks/databricks-sdk-go/experimental/mocks" + sdkpipelines "github.com/databricks/databricks-sdk-go/service/pipelines" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" ) func TestLooksLikeUUID(t *testing.T) { @@ -13,3 +19,67 @@ func TestLooksLikeUUID(t *testing.T) { func TestLooksLikeUUID_resourceName(t *testing.T) { assert.False(t, looksLikeUUID("my-pipeline-key")) } + +func TestListPipelinesTableConfig(t *testing.T) { + cmd := newListPipelines() + + cfg := tableview.GetConfig(cmd) + require.NotNil(t, cfg) + require.Len(t, cfg.Columns, 3) + require.NotNil(t, cfg.Search) + + pipeline := sdkpipelines.PipelineStateInfo{ + PipelineId: "pipeline-id", + Name: "pipeline-name", + State: sdkpipelines.PipelineStateIdle, + } + + assert.Equal(t, "pipeline-id", cfg.Columns[0].Extract(pipeline)) + assert.Equal(t, "pipeline-name", cfg.Columns[1].Extract(pipeline)) + assert.Equal(t, "IDLE", cfg.Columns[2].Extract(pipeline)) +} + +func TestListPipelinesSearchEscapesLikeWildcards(t *testing.T) { + cmd := newListPipelines() + + cfg := tableview.GetConfig(cmd) + require.NotNil(t, cfg) + require.NotNil(t, cfg.Search) + + m := mocks.NewMockWorkspaceClient(t) + m.GetMockPipelinesAPI().EXPECT(). + ListPipelines(mock.Anything, sdkpipelines.ListPipelinesRequest{ + Filter: "name LIKE '%foo''\\%\\_bar%'", + }). + Return(nil) + + ctx := cmdctx.SetWorkspaceClient(t.Context(), m.WorkspaceClient) + assert.NotNil(t, cfg.Search.NewIterator(ctx, "foo'%_bar")) +} + +func TestListPipelinesSearchDisabledWhenFilterSet(t *testing.T) { + cmd := newListPipelines() + + err := cmd.Flags().Set("filter", "state = 'RUNNING'") + require.NoError(t, err) + + cfg := tableview.GetConfig(cmd) + require.NotNil(t, cfg) + require.NotNil(t, cfg.Search) + + // The pipelines API does not support composite filters, so the + // PreRunE hook calls disableSearchIfFilterSet to nil out search. + disableSearchIfFilterSet(cmd) + assert.Nil(t, cfg.Search) +} + +func TestListPipelinesSearchNotDisabledWithoutFilter(t *testing.T) { + cmd := newListPipelines() + + cfg := tableview.GetConfig(cmd) + require.NotNil(t, cfg) + require.NotNil(t, cfg.Search) + + disableSearchIfFilterSet(cmd) + assert.NotNil(t, cfg.Search) +} diff --git a/cmd/workspace/repos/overrides.go b/cmd/workspace/repos/overrides.go index 8110c2aa48..0b3852d0ff 100644 --- a/cmd/workspace/repos/overrides.go +++ b/cmd/workspace/repos/overrides.go @@ -11,6 +11,7 @@ import ( "github.com/databricks/cli/libs/cmdio" "github.com/databricks/cli/libs/diag" "github.com/databricks/cli/libs/flags" + "github.com/databricks/cli/libs/tableview" "github.com/databricks/databricks-sdk-go" "github.com/databricks/databricks-sdk-go/service/workspace" "github.com/spf13/cobra" @@ -20,6 +21,23 @@ func listOverride(listCmd *cobra.Command, listReq *workspace.ListReposRequest) { listCmd.Annotations["template"] = cmdio.Heredoc(` {{range .}}{{green "%d" .Id}} {{.Path}} {{.Branch|blue}} {{.Url|cyan}} {{end}}`) + + columns := []tableview.ColumnDef{ + {Header: "ID", Extract: func(v any) string { + return strconv.FormatInt(v.(workspace.RepoInfo).Id, 10) + }}, + {Header: "Path", Extract: func(v any) string { + return v.(workspace.RepoInfo).Path + }}, + {Header: "Branch", Extract: func(v any) string { + return v.(workspace.RepoInfo).Branch + }}, + {Header: "URL", Extract: func(v any) string { + return v.(workspace.RepoInfo).Url + }}, + } + + tableview.RegisterConfig(listCmd, tableview.TableConfig{Columns: columns}) } func createOverride(createCmd *cobra.Command, createReq *workspace.CreateRepoRequest) { diff --git a/cmd/workspace/schemas/overrides.go b/cmd/workspace/schemas/overrides.go index ba4c65ce73..625c92f3d7 100644 --- a/cmd/workspace/schemas/overrides.go +++ b/cmd/workspace/schemas/overrides.go @@ -2,6 +2,7 @@ package schemas 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" ) @@ -12,6 +13,20 @@ func listOverride(listCmd *cobra.Command, listReq *catalog.ListSchemasRequest) { listCmd.Annotations["template"] = cmdio.Heredoc(` {{range .}}{{.FullName|green}} {{.Owner|cyan}} {{.Comment}} {{end}}`) + + columns := []tableview.ColumnDef{ + {Header: "Full Name", Extract: func(v any) string { + return v.(catalog.SchemaInfo).FullName + }}, + {Header: "Owner", Extract: func(v any) string { + return v.(catalog.SchemaInfo).Owner + }}, + {Header: "Comment", MaxWidth: 40, Extract: func(v any) string { + return v.(catalog.SchemaInfo).Comment + }}, + } + + tableview.RegisterConfig(listCmd, tableview.TableConfig{Columns: columns}) } func init() { diff --git a/cmd/workspace/serving-endpoints/overrides.go b/cmd/workspace/serving-endpoints/overrides.go new file mode 100644 index 0000000000..611428f18d --- /dev/null +++ b/cmd/workspace/serving-endpoints/overrides.go @@ -0,0 +1,35 @@ +package serving_endpoints + +import ( + "github.com/databricks/cli/libs/cmdio" + "github.com/databricks/cli/libs/tableview" + "github.com/databricks/databricks-sdk-go/service/serving" + "github.com/spf13/cobra" +) + +func listOverride(listCmd *cobra.Command) { + listCmd.Annotations["template"] = cmdio.Heredoc(` + {{range .}}{{green "%s" .Name}} {{if .State}}{{.State.Ready}}{{end}} {{.Creator}} + {{end}}`) + + columns := []tableview.ColumnDef{ + {Header: "Name", Extract: func(v any) string { + return v.(serving.ServingEndpoint).Name + }}, + {Header: "State", Extract: func(v any) string { + if v.(serving.ServingEndpoint).State != nil { + return string(v.(serving.ServingEndpoint).State.Ready) + } + return "" + }}, + {Header: "Creator", Extract: func(v any) string { + return v.(serving.ServingEndpoint).Creator + }}, + } + + tableview.RegisterConfig(listCmd, tableview.TableConfig{Columns: columns}) +} + +func init() { + listOverrides = append(listOverrides, listOverride) +} diff --git a/cmd/workspace/serving-endpoints/overrides_test.go b/cmd/workspace/serving-endpoints/overrides_test.go new file mode 100644 index 0000000000..1ab6f39dad --- /dev/null +++ b/cmd/workspace/serving-endpoints/overrides_test.go @@ -0,0 +1,58 @@ +package serving_endpoints + +import ( + "testing" + + "github.com/databricks/cli/libs/tableview" + "github.com/databricks/databricks-sdk-go/service/serving" + "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, 3) + + tests := []struct { + name string + endpoint serving.ServingEndpoint + wantName string + wantState string + wantCreator string + }{ + { + name: "with state", + endpoint: serving.ServingEndpoint{ + Name: "endpoint", + Creator: "user@example.com", + State: &serving.EndpointState{ + Ready: serving.EndpointStateReadyReady, + }, + }, + wantName: "endpoint", + wantState: "READY", + wantCreator: "user@example.com", + }, + { + name: "nil state", + endpoint: serving.ServingEndpoint{ + Name: "endpoint", + Creator: "user@example.com", + }, + wantName: "endpoint", + wantState: "", + wantCreator: "user@example.com", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.wantName, cfg.Columns[0].Extract(tt.endpoint)) + assert.Equal(t, tt.wantState, cfg.Columns[1].Extract(tt.endpoint)) + assert.Equal(t, tt.wantCreator, cfg.Columns[2].Extract(tt.endpoint)) + }) + } +} diff --git a/cmd/workspace/tables/overrides.go b/cmd/workspace/tables/overrides.go index a0849ada7f..157d62daf9 100644 --- a/cmd/workspace/tables/overrides.go +++ b/cmd/workspace/tables/overrides.go @@ -2,6 +2,7 @@ package tables 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" ) @@ -12,6 +13,17 @@ func listOverride(listCmd *cobra.Command, listReq *catalog.ListTablesRequest) { listCmd.Annotations["template"] = cmdio.Heredoc(` {{range .}}{{.FullName|green}} {{blue "%s" .TableType}} {{end}}`) + + columns := []tableview.ColumnDef{ + {Header: "Full Name", Extract: func(v any) string { + return v.(catalog.TableInfo).FullName + }}, + {Header: "Table Type", Extract: func(v any) string { + return string(v.(catalog.TableInfo).TableType) + }}, + } + + tableview.RegisterConfig(listCmd, tableview.TableConfig{Columns: columns}) } func init() { diff --git a/cmd/workspace/volumes/overrides.go b/cmd/workspace/volumes/overrides.go new file mode 100644 index 0000000000..0a4f645de3 --- /dev/null +++ b/cmd/workspace/volumes/overrides.go @@ -0,0 +1,32 @@ +package volumes + +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" +) + +func listOverride(listCmd *cobra.Command, listReq *catalog.ListVolumesRequest) { + listCmd.Annotations["template"] = cmdio.Heredoc(` + {{range .}}{{green "%s" .Name}} {{.VolumeType}} {{.FullName}} + {{end}}`) + + columns := []tableview.ColumnDef{ + {Header: "Name", Extract: func(v any) string { + return v.(catalog.VolumeInfo).Name + }}, + {Header: "Volume Type", Extract: func(v any) string { + return string(v.(catalog.VolumeInfo).VolumeType) + }}, + {Header: "Full Name", Extract: func(v any) string { + return v.(catalog.VolumeInfo).FullName + }}, + } + + tableview.RegisterConfig(listCmd, tableview.TableConfig{Columns: columns}) +} + +func init() { + listOverrides = append(listOverrides, listOverride) +} diff --git a/cmd/workspace/warehouses/overrides.go b/cmd/workspace/warehouses/overrides.go index 9457557d00..edc58ad681 100644 --- a/cmd/workspace/warehouses/overrides.go +++ b/cmd/workspace/warehouses/overrides.go @@ -2,6 +2,7 @@ package warehouses 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" ) @@ -12,6 +13,23 @@ func listOverride(listCmd *cobra.Command, listReq *sql.ListWarehousesRequest) { listCmd.Annotations["template"] = cmdio.Heredoc(` {{range .}}{{.Id|green}} {{.Name|cyan}} {{.ClusterSize|cyan}} {{if eq .State "RUNNING"}}{{"RUNNING"|green}}{{else if eq .State "STOPPED"}}{{"STOPPED"|red}}{{else}}{{blue "%s" .State}}{{end}} {{end}}`) + + columns := []tableview.ColumnDef{ + {Header: "ID", Extract: func(v any) string { + return v.(sql.EndpointInfo).Id + }}, + {Header: "Name", Extract: func(v any) string { + return v.(sql.EndpointInfo).Name + }}, + {Header: "Size", Extract: func(v any) string { + return v.(sql.EndpointInfo).ClusterSize + }}, + {Header: "State", Extract: func(v any) string { + return string(v.(sql.EndpointInfo).State) + }}, + } + + tableview.RegisterConfig(listCmd, tableview.TableConfig{Columns: columns}) } func init() { diff --git a/cmd/workspace/workspace/overrides.go b/cmd/workspace/workspace/overrides.go index c57209b554..56e2e74f71 100644 --- a/cmd/workspace/workspace/overrides.go +++ b/cmd/workspace/workspace/overrides.go @@ -6,10 +6,12 @@ import ( "fmt" "net/http" "os" + "strconv" "strings" "github.com/databricks/cli/libs/cmdctx" "github.com/databricks/cli/libs/cmdio" + "github.com/databricks/cli/libs/tableview" "github.com/databricks/databricks-sdk-go/apierr" "github.com/databricks/databricks-sdk-go/service/workspace" "github.com/spf13/cobra" @@ -22,6 +24,23 @@ func listOverride(listCmd *cobra.Command, listReq *workspace.ListWorkspaceReques listCmd.Annotations["template"] = cmdio.Heredoc(` {{range .}}{{green "%d" .ObjectId}} {{blue "%s" .ObjectType}} {{cyan "%s" .Language}} {{.Path|cyan}} {{end}}`) + + columns := []tableview.ColumnDef{ + {Header: "ID", Extract: func(v any) string { + return strconv.FormatInt(v.(workspace.ObjectInfo).ObjectId, 10) + }}, + {Header: "Type", Extract: func(v any) string { + return string(v.(workspace.ObjectInfo).ObjectType) + }}, + {Header: "Language", Extract: func(v any) string { + return string(v.(workspace.ObjectInfo).Language) + }}, + {Header: "Path", Extract: func(v any) string { + return v.(workspace.ObjectInfo).Path + }}, + } + + tableview.RegisterConfig(listCmd, tableview.TableConfig{Columns: columns}) } func exportOverride(exportCmd *cobra.Command, exportReq *workspace.ExportRequest) {