Add endless-scrolling TUI table for interactive list commands#4729
Add endless-scrolling TUI table for interactive list commands#4729simonfaltum wants to merge 30 commits intomainfrom
Conversation
|
Commit: be88c2e |
53b85d2 to
64f2b98
Compare
64f2b98 to
ef8c413
Compare
Co-authored-by: Isaac
1bf0772 to
e672906
Compare
shreyas-goenka
left a comment
There was a problem hiding this comment.
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
8fa51c9 to
d7a7104
Compare
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.
## Why PR #4731 added curated TUI table overrides for 15 list commands. This follow-up covers 5 additional commands that are among the most frequently used in the CLI, but were missing curated columns. ## Changes Before: these 5 commands used either generic text templates (secrets, cluster-policies) or raw JSON output (lakeview, pipeline events) with no curated TUI table columns. Now: all 5 register curated TableConfig overrides so they show useful columns in the interactive TUI. Commands that had no text template override (lakeview list, pipelines list-pipeline-events) also get template annotations for the non-interactive fallback. This PR stacks on #4731. It only adds per-command overrides, no engine changes. ### Post-review fixes - Sanitize control whitespace (`\n`, `\r`, `\t`) in pipeline event messages to prevent table row corruption - Increase MaxWidth for pipeline event Message column from 60 to 200 (pragmatic cap until non-destructive clipping is implemented) - Remove redundant `PaginatedModel` type alias, use `FinalModel` interface instead - Remove duplicate `TestPaginatedErrAccessor` test - Trim verbose MaxWidth truncation comment ## Test plan - `go build ./...` - `make checks` passes - `make lintfull` passes (0 issues) - Manual smoke test: verify curated columns for `secrets list-scopes`, `lakeview list`, `pipelines list-pipeline-events`
- Use rune-aware length checks and slicing in renderContent and computeWidths to prevent corrupting multi-byte characters - Check ctx.Err() after HasNext returns false so context cancellation surfaces as an error instead of masquerading as normal exhaustion - Guard AutoDetect extractors against non-struct values to prevent panic - Remove unused RunPaginated (RenderIterator calls NewPaginatedProgram directly) and unused WithMaxItems - Add comment explaining the retry-by-scrolling behavior on fetch errors Co-authored-by: Isaac
… recompute - Rewrite highlightSearch to work in rune-space so case-folding length changes (e.g. "ß" to "ss") do not misalign highlighted spans - Reset limitReached in executeSearch and restorePreSearchState so the footer does not incorrectly show limit info after search transitions - Call computeWidths() in restorePreSearchState before rendering so separator widths are recalculated for the restored data Co-authored-by: Isaac
Approval status: pending
|
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 jsonkeep the existing behavior. Commands without an explicit table config continue to use template rendering.Implementation:
tableview.gointocommon.gotableviewconfig, registry, and wrapper typesexperimental/aitoolsto the shared static table rendererPost-review fixes
utf8.DecodeLastRuneInString)RunPaginatedsilently dropping model-level fetch errors (now checksFinalModel.Err()likerender.go)restorePreSearchStateto eliminate duplicated search-restore logictea.KeySpacein both paginated and non-paginated tables)loadingandsearchingconcerns:loadingis purely "fetch in-flight",searchingflag blocksmaybeFetchduring search input mode (fixes stuck pagination and overlapping fetch races)Test plan
go test ./libs/tableview/... ./libs/cmdio/... ./cmd/root/... ./experimental/aitools/cmd/...--output json: verify existing output is unchangedmake checkspassesmake lintfullpasses (0 issues)