|
| 1 | +package tui |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "fmt" |
| 6 | + "time" |
| 7 | + |
| 8 | + "github.com/databricks/cli/libs/cmdio" |
| 9 | +) |
| 10 | + |
| 11 | +type spinnerMessage struct { |
| 12 | + text string |
| 13 | + duration time.Duration |
| 14 | +} |
| 15 | + |
| 16 | +var spinnerMessages = []spinnerMessage{ |
| 17 | + {"Initializing...", time.Second}, |
| 18 | + {"Loading configuration", time.Second}, |
| 19 | + {"Connecting to workspace", time.Second}, |
| 20 | + {"Processing files", time.Second}, |
| 21 | + {"Finalizing", time.Second}, |
| 22 | +} |
| 23 | + |
| 24 | +// databricksFeatures is a stable list of Databricks product / feature names |
| 25 | +// used as fixture data for the prompt scenarios. Drawn from the public docs |
| 26 | +// (https://docs.databricks.com) so the demo data looks like something a user |
| 27 | +// would actually encounter. |
| 28 | +var databricksFeatures = []string{ |
| 29 | + "unity-catalog", |
| 30 | + "delta-lake", |
| 31 | + "delta-sharing", |
| 32 | + "photon", |
| 33 | + "mlflow", |
| 34 | + "mosaic-ai", |
| 35 | + "genie", |
| 36 | + "lakeflow-connect", |
| 37 | + "lakeflow-jobs", |
| 38 | + "vector-search", |
| 39 | + "model-serving", |
| 40 | + "feature-store", |
| 41 | + "databricks-sql", |
| 42 | + "ai-playground", |
| 43 | + "foundation-models", |
| 44 | + "lakehouse-monitoring", |
| 45 | + "liquid-clustering", |
| 46 | + "predictive-optimization", |
| 47 | + "governed-tags", |
| 48 | + "lakeflow-designer", |
| 49 | +} |
| 50 | + |
| 51 | +// buildItems uses zero-padded ids so the alphabetical Select scenario has |
| 52 | +// a stable sort order. |
| 53 | +func buildItems(n int) []cmdio.Tuple { |
| 54 | + n = min(n, len(databricksFeatures)) |
| 55 | + items := make([]cmdio.Tuple, 0, n) |
| 56 | + for i := range n { |
| 57 | + items = append(items, cmdio.Tuple{ |
| 58 | + Name: databricksFeatures[i], |
| 59 | + Id: fmt.Sprintf("id-%02d", i+1), |
| 60 | + }) |
| 61 | + } |
| 62 | + return items |
| 63 | +} |
| 64 | + |
| 65 | +// buildFilterItems returns 15 items where 5 share the substring "lake", so |
| 66 | +// progressive typing narrows the list, and a non-matching substring ("xyz") |
| 67 | +// hits the "No results" path. |
| 68 | +func buildFilterItems() []cmdio.Tuple { |
| 69 | + names := []string{ |
| 70 | + "lakehouse-monitoring", |
| 71 | + "lakeflow-connect", |
| 72 | + "lakeflow-jobs", |
| 73 | + "delta-lake", |
| 74 | + "lakebase-postgres", |
| 75 | + "unity-catalog", |
| 76 | + "mosaic-ai", |
| 77 | + "vector-search", |
| 78 | + "model-serving", |
| 79 | + "feature-store", |
| 80 | + "ai-playground", |
| 81 | + "genie-spaces", |
| 82 | + "mlflow-tracking", |
| 83 | + "liquid-clustering", |
| 84 | + "predictive-optimization", |
| 85 | + } |
| 86 | + items := make([]cmdio.Tuple, 0, len(names)) |
| 87 | + for i, name := range names { |
| 88 | + items = append(items, cmdio.Tuple{ |
| 89 | + Name: name, |
| 90 | + Id: fmt.Sprintf("id-%02d", i+1), |
| 91 | + }) |
| 92 | + } |
| 93 | + return items |
| 94 | +} |
| 95 | + |
| 96 | +// buildLongItems uses fully-qualified workspace URLs as ids so that the |
| 97 | +// rendered field overflows a typical terminal width. |
| 98 | +func buildLongItems() []cmdio.Tuple { |
| 99 | + hosts := []string{ |
| 100 | + "https://adb-1234567890123456.78.azuredatabricks.net/?o=1234567890123456", |
| 101 | + "https://adb-2345678901234567.89.azuredatabricks.net/?o=2345678901234567", |
| 102 | + "https://acme-prod.cloud.databricks.com/?o=3456789012345678", |
| 103 | + "https://acme-staging.cloud.databricks.com/?o=4567890123456789", |
| 104 | + "https://acme-dev.cloud.databricks.com/?o=5678901234567890", |
| 105 | + "https://1234567890123456.7.gcp.databricks.com/?o=6789012345678901", |
| 106 | + "https://2345678901234567.8.gcp.databricks.com/?o=7890123456789012", |
| 107 | + "https://field-eng-east.cloud.databricks.com/?o=8901234567890123", |
| 108 | + } |
| 109 | + items := make([]cmdio.Tuple, 0, len(hosts)) |
| 110 | + for i, host := range hosts { |
| 111 | + items = append(items, cmdio.Tuple{ |
| 112 | + Name: fmt.Sprintf("workspace-%02d", i+1), |
| 113 | + Id: host, |
| 114 | + }) |
| 115 | + } |
| 116 | + return items |
| 117 | +} |
| 118 | + |
| 119 | +// clusterItem mirrors libs/databrickscfg/cfgpickers/clusters.go's |
| 120 | +// compatibleCluster: State, Access, and Runtime are exposed as methods so |
| 121 | +// the Active/Inactive templates exercise text/template's method-resolution |
| 122 | +// path, and State returns a pre-rendered colored string (matching the |
| 123 | +// renderedState cache in production) so the demo also exercises ANSI codes |
| 124 | +// emitted from inside a template. |
| 125 | +type clusterItem struct { |
| 126 | + Name string |
| 127 | + Id string |
| 128 | + |
| 129 | + access string |
| 130 | + runtimeName string |
| 131 | + renderedState string |
| 132 | +} |
| 133 | + |
| 134 | +func (c clusterItem) Access() string { return c.access } |
| 135 | +func (c clusterItem) Runtime() string { return c.runtimeName } |
| 136 | +func (c clusterItem) State() string { return c.renderedState } |
| 137 | + |
| 138 | +func buildClusterItems(ctx context.Context) []clusterItem { |
| 139 | + green := func(s string) string { return cmdio.Green(ctx, s) } |
| 140 | + red := func(s string) string { return cmdio.Red(ctx, s) } |
| 141 | + blue := func(s string) string { return cmdio.Blue(ctx, s) } |
| 142 | + return []clusterItem{ |
| 143 | + {Name: "shared-autoscaling-prod", Id: "0123-456789-abcdef01", access: "Shared", runtimeName: "DBR 14.3 LTS", renderedState: green("RUNNING")}, |
| 144 | + {Name: "ml-gpu-experiments", Id: "0123-456789-abcdef02", access: "Assigned", runtimeName: "DBR 15.0 ML", renderedState: red("TERMINATED")}, |
| 145 | + {Name: "job-compute-bronze-etl", Id: "0123-456789-abcdef03", access: "Shared", runtimeName: "DBR 13.3 LTS", renderedState: green("RUNNING")}, |
| 146 | + {Name: "interactive-analytics", Id: "0123-456789-abcdef04", access: "Assigned", runtimeName: "DBR 14.3", renderedState: blue("PENDING")}, |
| 147 | + {Name: "photon-streaming-realtime", Id: "0123-456789-abcdef05", access: "Shared", runtimeName: "DBR 14.3 Photon", renderedState: green("RUNNING")}, |
| 148 | + {Name: "single-node-dev", Id: "0123-456789-abcdef06", access: "Assigned", runtimeName: "DBR 14.3 LTS", renderedState: red("TERMINATED")}, |
| 149 | + {Name: "all-purpose-shared", Id: "0123-456789-abcdef07", access: "Shared", runtimeName: "DBR 15.0", renderedState: green("RUNNING")}, |
| 150 | + {Name: "legacy-data-eng", Id: "0123-456789-abcdef08", access: "Assigned", runtimeName: "DBR 12.2 LTS", renderedState: red("TERMINATED")}, |
| 151 | + } |
| 152 | +} |
| 153 | + |
| 154 | +// profileItem mirrors the profile picker in cmd/auth/token.go: regular items |
| 155 | +// have a Host, the trailing meta items do not (so the {{if .Host}} branch fires). |
| 156 | +type profileItem struct { |
| 157 | + Name string |
| 158 | + Host string |
| 159 | +} |
| 160 | + |
| 161 | +// buildProfileItems returns 6 profile-shaped items across AWS / Azure / GCP |
| 162 | +// hosts plus the two trailing meta-rows ("Create a new profile", "Enter a |
| 163 | +// host URL manually") used by the real profile picker. |
| 164 | +func buildProfileItems() []profileItem { |
| 165 | + return []profileItem{ |
| 166 | + {Name: "DEFAULT", Host: "https://acme.cloud.databricks.com"}, |
| 167 | + {Name: "production", Host: "https://acme-prod.cloud.databricks.com"}, |
| 168 | + {Name: "staging", Host: "https://acme-stg.cloud.databricks.com"}, |
| 169 | + {Name: "field-eng", Host: "https://field-eng.cloud.databricks.com"}, |
| 170 | + {Name: "azure-personal", Host: "https://adb-1234567890123456.78.azuredatabricks.net"}, |
| 171 | + {Name: "gcp-sandbox", Host: "https://1234567890123456.7.gcp.databricks.com"}, |
| 172 | + {Name: "Create a new profile"}, |
| 173 | + {Name: "Enter a host URL manually"}, |
| 174 | + } |
| 175 | +} |
0 commit comments