-
Notifications
You must be signed in to change notification settings - Fork 5
feat: add prominent loading spinner during query execution #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Add animated braille spinner overlay in the grid area when queries run - Show elapsed time in the loading overlay - Increase event loop polling frequency (16ms vs 50ms) during queries to keep UI responsive and animations smooth - Upgrade status bar running indicator to Priority::Critical with bold yellow styling for better visibility - Add throbber-widgets-tui 0.9 dependency for spinner widget This addresses the issue where the UI appeared frozen during long-running queries and the existing "⏳ running" indicator was too subtle.
|
Caution Review failedThe pull request is closed. Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro Disabled knowledge base sources:
📒 Files selected for processing (1)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
crates/tsql/src/app/app.rs (4)
726-730: Consider keeping timer/throbber state co-located withDbSession(optional), but current wiring is fine.
Right nowdb.runninglives inDbSessionwhilequery_start_time/throbber_statelive inApp. This works, but if you anticipate more “running UI” state, it may be cleaner to group them (or wrap into a small struct) to avoid drift.Also applies to: 844-846
1254-1313: Guard overlay rendering for extremely smallgrid_areato avoid zero-area widget edge cases.
If the terminal is tiny,overlay_area/innercan end up with 0 height/width, and some widgets can behave oddly. Consider an early return like “only render overlay ifgrid_area.width >= 20 && grid_area.height >= 3” (or ifinner.height >= 2).- if self.db.running { + if self.db.running && grid_area.width >= 20 && grid_area.height >= 3 { // Calculate centered overlay area (40% width, minimum 20 chars, 5 lines height) let overlay_width = (grid_area.width * 40 / 100).max(20).min(grid_area.width); let overlay_height = 5u16.min(grid_area.height); @@ - // Layout for spinner and elapsed time + // Layout for spinner and elapsed time let chunks = Layout::default() .direction(Direction::Vertical) .constraints([ Constraint::Length(1), // Spinner with label Constraint::Length(1), // Elapsed time ]) .split(inner);
4961-4964: Elapsed timer is only set forexecute_query(); decide if meta queries / cell updates should also set it.
db.runningbecomes true inexecute_meta_query()andexecute_cell_update(), so the overlay shows, but elapsed time won’t (sincequery_start_timeremainsNone). If the intent is “elapsed for any running operation”, setquery_start_time = Some(Instant::now())in those paths too.Also applies to: 3277-3286, 3021-3028
5137-5140: Clearquery_start_timeonDbEvent::CellUpdatedtoo (defensive consistency).
TodayCellUpdateddoesn’t setquery_start_time, so it won’t leak, but clearing it there makes the state machine harder to accidentally break later (especially if you later add elapsed timing for updates).DbEvent::CellUpdated { row, col, value } => { self.db.running = false; + self.query_start_time = None; // Update the grid cell if let Some(grid_row) = self.grid.rows.get_mut(row) {Also applies to: 5181-5190, 5202-5211
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (3)
Cargo.toml(1 hunks)crates/tsql/Cargo.toml(1 hunks)crates/tsql/src/app/app.rs(11 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.rs: Runcargo fmt --allto format the code before committing changes
Runcargo clippy --all --all-targets -- -D warningsto check for lints and fix them before pushing changes
**/*.rs: Userustfmtwith default settings as the source of truth for code formatting in Rust files
Usesnake_casefor function and module names in Rust
UseCamelCasefor type and trait names in Rust
UseSCREAMING_SNAKE_CASEfor constant names in Rust
Keep changes focused and prefer small, composable helper functions over large UI/app methods
Place unit tests colocated with code using#[cfg(test)]modules for pure logic testing
Files:
crates/tsql/src/app/app.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Test (windows-latest)
🔇 Additional comments (5)
Cargo.toml (1)
55-57: LGTM: dependency added in the right place; sanity-check for duplicates and advisories.
Given this is a new third-party dependency, double-check there isn’t anotherthrobber-widgets-tuideclaration (different version/features) elsewhere and consider running your usual advisory scan (e.g.,cargo audit) in CI.crates/tsql/src/app/app.rs (3)
14-17: Confirmthrobber-widgets-tuiAPI usage matches v0.9 (andratatui0.29).
The imports andThrobberStateusage look straightforward, but since this is an external UI widget crate, please confirmBRAILLE_SIX,calc_next(), andrender_stateful_widget()are the intended v0.9 API surface for your ratatui version.Also applies to: 47-47
990-994: Nice: dynamic polling + per-tick throbber advance; please manually verify CPU impact.
At 16ms polling you’ll effectively redraw ~60 FPS while a query runs. That’s likely fine, but it’s worth a quick manual check on slower terminals/remote SSH to ensure it doesn’t peg a core.Also applies to: 1654-1662
5310-5319: Status-line “running” segment upgrade is a good UX improvement.
Making itPriority::Criticalwith bold yellow styling should address the “app appears frozen” perception even without the overlay.crates/tsql/Cargo.toml (1)
48-50: Dependency verification complete:throbber-widgets-tui0.9 is fully compatible with your setup. The crate is designed for ratatui (confirmed compatible with 0.29), has MSRV of 1.74.0 (satisfied by workspace 1.80), and uses MIT license matching the workspace.
- Add minimum grid area guard (width >= 20, height >= 5) to prevent overlay rendering issues on small terminals - Set query_start_time in execute_cell_update and execute_meta_query for consistent timing display across all query types - Clear query_start_time on CellUpdated event for defensive consistency
The timing_info segment already shows "N rows (Xms)", so last_status now only shows "Ready" or "[truncated]" instead of duplicating the row count and timing information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
crates/tsql/src/app/app.rs (2)
726-729: New App state looks fine; consider grouping spinner/timing state into a small struct.Right now
Appis already very large;QueryRunUi { throbber_state, query_start_time }would keep this more maintainable without changing behavior.Also applies to: 844-845
990-993: Tick-rate change achieves smooth animation, but consider making the idle redraw cheaper/configurable.20 FPS redraw while idle (50ms) may be more CPU than needed for a mostly-static screen. If you want to keep it snappy, consider (a) increasing idle to ~100–200ms, or (b) only forcing redraws on state changes while idle.
Also applies to: 1654-1661
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
crates/tsql/src/app/app.rs(14 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.rs: Runcargo fmt --allto format the code before committing changes
Runcargo clippy --all --all-targets -- -D warningsto check for lints and fix them before pushing changes
**/*.rs: Userustfmtwith default settings as the source of truth for code formatting in Rust files
Usesnake_casefor function and module names in Rust
UseCamelCasefor type and trait names in Rust
UseSCREAMING_SNAKE_CASEfor constant names in Rust
Keep changes focused and prefer small, composable helper functions over large UI/app methods
Place unit tests colocated with code using#[cfg(test)]modules for pure logic testing
Files:
crates/tsql/src/app/app.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Test (windows-latest)
🔇 Additional comments (4)
crates/tsql/src/app/app.rs (4)
1254-1313: Loading overlay rendering is solid; layering order works.Nice touch with
Clear+ centered block + elapsed time, and thegrid_areasize guard prevents ugly layouts.
3026-3029: Query timer is started consistently across query/update/meta paths.This aligns well with the overlay + elapsed UX.
Also applies to: 3285-3288, 4963-4966
5313-5321: Promoted status “running” indicator is clear and consistent with the new overlay.Priority + bold styling should prevent the “app frozen” perception.
14-16: No changes needed—all imports are compatible with your locked dependency versions.
ratatui::layout::Alignment,ratatui::style::Modifier, andthrobber_widgets_tui::{Throbber, ThrobberState, BRAILLE_SIX}are all properly exported in ratatui 0.29.0 and throbber-widgets-tui 0.9.0 respectively. The usage patterns in the code (e.g.,Alignment::Center,Throbber::default().throbber_set(BRAILLE_SIX),ThrobberState::default()) match the documented APIs for both crates.
| self.db.running = false; | ||
| self.query_start_time = None; | ||
| self.db.last_command_tag = result.command_tag.clone(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clear query_start_time in all paths that force db.running = false (e.g., connect failures / disconnect).
Right now, some branches set self.db.running = false but don’t reset query_start_time (e.g., DbEvent::ConnectError, DbEvent::ConnectionLost, and :disconnect). Overlay won’t show because it’s gated by db.running, but stale state is easy to avoid.
diff --git a/crates/tsql/src/app/app.rs b/crates/tsql/src/app/app.rs
@@
DbEvent::ConnectError { error } => {
self.db.status = DbStatus::Error;
self.db.client = None;
self.db.running = false;
+ self.query_start_time = None;
self.current_connection_name = None;
self.last_status = Some("Connect failed (see error)".to_string());
self.last_error = Some(format!("Connection error: {}", error));
}
DbEvent::ConnectionLost { error } => {
self.db.status = DbStatus::Error;
self.db.client = None;
self.db.running = false;
+ self.query_start_time = None;
self.current_connection_name = None;
self.last_status = Some("Connection lost (see error)".to_string());
self.last_error = Some(format!("Connection lost: {}", error));
}
@@
"disconnect" | "dc" => {
self.db.client = None;
self.db.cancel_token = None;
self.db.status = DbStatus::Disconnected;
self.db.running = false;
+ self.query_start_time = None;
self.last_status = Some("Disconnected".to_string());
}Also applies to: 5183-5186, 5189-5192, 5204-5207
🤖 Prompt for AI Agents
In crates/tsql/src/app/app.rs around lines 5140-5142 (and also the similar
blocks at 5183-5186, 5189-5192, 5204-5207), some branches set self.db.running =
false but do not clear self.query_start_time, leaving stale state; update each
branch that forces db.running = false (e.g., DbEvent::ConnectError,
DbEvent::ConnectionLost, :disconnect handlers and any other early-return paths
that set running=false) to also set self.query_start_time = None immediately
after setting self.db.running = false so the overlay/state is fully cleared.
Summary
Problem
When queries execute in tsql, the UI blocks completely and the current loading indicator ("⏳ running" in the status bar) is too subtle, making the application appear frozen.
Solution
Testing
cargo fmt --allpassescargo clippy --all --all-targets -- -D warningspassesSummary by CodeRabbit
New Features
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.