Skip to content

Add endless-scrolling TUI table for interactive list commands#4729

Open
simonfaltum wants to merge 6 commits intomainfrom
simonfaltum/list-tui-paginated
Open

Add endless-scrolling TUI table for interactive list commands#4729
simonfaltum wants to merge 6 commits intomainfrom
simonfaltum/list-tui-paginated

Conversation

@simonfaltum
Copy link
Member

@simonfaltum simonfaltum commented Mar 12, 2026

Why

Large list commands are hard to use in a terminal today. They print the full result set before users can do anything, which is slow for big lists and makes it hard to browse results. Interactive terminals should get a faster, more navigable experience without changing scripted output.

Changes

Before: list commands drained the full paginated iterator and rendered everything through text templates or JSON.

Now: when the CLI is running interactively (TTY stdin + stdout + stderr, color enabled), list commands with a registered table configuration open a scrollable TUI table that loads more rows on demand. Piped output and --output json keep the existing behavior. Commands without an explicit table config continue to use template rendering.

Implementation:

  • Extract shared styles, constants, and helpers from tableview.go into common.go
  • Add reusable tableview config, registry, and wrapper types
  • Add a Bubble Tea paginated model with fetch-on-demand, cursor navigation, horizontal scrolling, and optional server-side search
  • Route interactive list rendering through the TUI when a TableConfig is registered, fall through to templates otherwise
  • Integrate with cmdio Tea program lifecycle (acquireTeaProgram/releaseTeaProgram)
  • Switch experimental/aitools to the shared static table renderer

Test plan

  • go test ./libs/tableview/... ./libs/cmdio/... ./cmd/root/... ./experimental/aitools/cmd/...
  • Manual smoke test in a TTY: verify the first page renders immediately and more rows load while scrolling
  • Manual smoke test with piped output and --output json: verify existing output is unchanged
  • make checks passes
  • make lintfull passes (0 issues)

@eng-dev-ecosystem-bot
Copy link
Collaborator

eng-dev-ecosystem-bot commented Mar 12, 2026

Commit: dbd2241

Run: 23059763837

Env 🔄​flaky 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
💚​ aws linux 8 7 268 787 6:05
💚​ aws windows 8 7 270 785 5:04
🔄​ aws-ucws linux 2 7 7 364 702 8:54
🔄​ aws-ucws windows 2 7 7 366 700 7:04
💚​ azure linux 2 9 271 785 5:49
💚​ azure windows 2 9 273 783 5:08
🔄​ azure-ucws linux 2 1 9 369 698 9:09
🔄​ azure-ucws windows 2 1 9 371 696 6:11
💚​ gcp linux 2 9 267 788 5:21
💚​ gcp windows 2 9 269 786 4:45
16 interesting tests: 7 SKIP, 6 RECOVERED, 3 flaky
Test Name aws linux aws windows aws-ucws linux aws-ucws windows azure linux azure windows azure-ucws linux azure-ucws windows gcp linux gcp windows
🔄​ TestAccept 💚​R 💚​R 💚​R 🔄​f 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
🙈​ TestAccept/bundle/resources/permissions 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
💚​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions 💚​R 💚​R 💚​R 💚​R 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
💚​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=direct 💚​R 💚​R 💚​R 💚​R
💚​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 💚​R 💚​R 💚​R 💚​R
💚​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions 💚​R 💚​R 💚​R 💚​R 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
💚​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=direct 💚​R 💚​R 💚​R 💚​R
💚​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 💚​R 💚​R 💚​R 💚​R
🙈​ TestAccept/bundle/resources/postgres_branches/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/recreate 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/update_protected 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/without_branch_id 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_endpoints/recreate 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/synced_database_tables/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🔄​ TestAccept/ssh/connect-serverless-gpu 🙈​s 🙈​s 🔄​f 🔄​f 🙈​s 🙈​s 🔄​f 🔄​f 🙈​s 🙈​s
🔄​ TestAccept/ssh/connection 💚​R 💚​R 🔄​f 💚​R 💚​R 💚​R 🔄​f 🔄​f 💚​R 💚​R
Top 20 slowest tests (at least 2 minutes):
duration env testname
3:45 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:31 aws-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:27 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:25 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:18 aws-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:15 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:15 aws-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:02 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:55 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:50 azure-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:42 azure windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:42 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:41 aws-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:40 azure-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:39 azure-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:37 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:22 azure-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:17 azure linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:13 azure linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:10 azure windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform

@simonfaltum simonfaltum force-pushed the simonfaltum/list-tui-paginated branch from 1bf0772 to e672906 Compare March 13, 2026 06:23
@simonfaltum simonfaltum marked this pull request as ready for review March 13, 2026 10:33
Copy link
Contributor

@shreyas-goenka shreyas-goenka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This review was posted by Claude (AI assistant). Shreyas will do a separate, more thorough review pass.

Priority: HIGH — Performance and design concerns in TUI table infrastructure

MAJOR: O(n) re-render on every keystroke

The search/filter functionality appears to re-render the entire table on each keystroke. For large result sets, this will cause noticeable lag. Consider debouncing the search input or using incremental filtering.

MAJOR: Partially-consumed iterator after search

When a user searches/filters, the iterator may have already been partially consumed. If the search is cleared, previously consumed items that didn't match won't be re-fetched. This could lead to confusing behavior where clearing a search shows fewer results than expected.

MEDIUM: Entire feature unreachable until follow-up PRs

This is 1535 lines of new code that is unreachable until the override PRs (#4731, #4732) land. Consider whether the infrastructure could be reviewed more effectively alongside at least one consumer.

What looks good

  • Clean separation of concerns between model, view, and update
  • Good use of Bubble Tea framework patterns
  • Table column configuration is flexible and well-designed

@simonfaltum simonfaltum force-pushed the simonfaltum/list-tui-paginated branch from 8fa51c9 to d7a7104 Compare March 13, 2026 12:40
Search input now triggers server-side filtering automatically after the
user stops typing for 200ms, instead of waiting for Enter. This prevents
redundant API calls on each keystroke while keeping the text input
responsive. Enter still executes search immediately, bypassing the
debounce.

Uses Bubble Tea's tick-based message pattern with a sequence counter to
discard stale debounce ticks when the user types additional characters
before the delay expires.
Fix four issues in the paginated TUI:

1. Entering search mode now sets loading=true to prevent maybeFetch from
   starting new fetches against the shared iterator while in search mode.
   In-flight fetches are discarded via the generation check.

2. executeSearch sets loading=true (was false) to prevent overlapping fetch
   commands when a quick scroll triggers maybeFetch before the first search
   fetch returns.

3. Pressing esc to close search now restores savedRows, savedIter, and
   savedExhaust (same as clearing the query via enter with empty input).

4. RenderIterator now checks the final model for application-level errors
   via the new FinalModel interface, since tea.Program.Run() only returns
   framework errors.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants