Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
820a10a
Ballista Text User Interface app
martin-g Feb 1, 2026
b85e915
Merge branch 'main' into ballusta-tui-in-cli-2
martin-g Feb 1, 2026
ef525b9
Align the contents of the Jobs & Metrics panes to the center
martin-g Feb 1, 2026
09c1580
Implement Debug for Views enum
martin-g Feb 1, 2026
883db23
Implement std Error & Display for TuiError
martin-g Feb 1, 2026
d205a5a
Improve the error handling in http_client
martin-g Feb 1, 2026
cfb841e
Tidy up the imports of the sub-modules
martin-g Feb 1, 2026
7ead2f5
Do not center the banner text
martin-g Feb 1, 2026
8af4683
Simplify the layout for the content panel
martin-g Feb 1, 2026
6bbb0a1
Log a warning if the event bus is not available
martin-g Feb 1, 2026
97ea334
Merge branch 'main' into ballusta-tui-in-cli-2
martin-g Feb 17, 2026
c6dfb59
Merge branch 'main' into ballusta-tui-in-cli-2
martin-g Feb 23, 2026
55845aa
Make it more obvious when a scheduler is up/down
martin-g Feb 23, 2026
fc48105
Do not fail if color_eyre fails to install.
martin-g Feb 23, 2026
4e99798
Format
martin-g Feb 24, 2026
2a86259
Move the Scheduler Info to the top-right area
martin-g Feb 24, 2026
72fb077
Add Dashboard > Jobs UI
martin-g Feb 24, 2026
8f9bcf8
fmt
martin-g Feb 24, 2026
510cd3f
Disable the top navigation if the scheduler is down
martin-g Feb 24, 2026
9f0e7d2
Delete unused code to fix the linter
martin-g Feb 24, 2026
3c75c53
Add widgets for the jobs in different state in Dashboard
martin-g Feb 24, 2026
31770b7
Merge branch 'main' into ballusta-tui-in-cli-2
martin-g Feb 26, 2026
1b783d4
Render the jobs stats in Dashboard view in colors
martin-g Feb 26, 2026
6857246
Add a footer with the key bindings
martin-g Feb 26, 2026
8a3b6fa
Make the help overlay smaller
martin-g Feb 26, 2026
7524096
Render the Prometheus metrics in a table
martin-g Feb 26, 2026
177f3dd
Use tui-big-text to render the banner
martin-g Feb 27, 2026
7963100
fmt + clippy
martin-g Feb 27, 2026
9147e12
Improve the rendering of the histogram data in the table
martin-g Feb 27, 2026
ceeb70f
Read the metric's HELP from scrape.docs
martin-g Feb 27, 2026
c6c827a
Do not panic if the file logger cannot be setup
martin-g Feb 27, 2026
cfd26cc
Merge branch 'main' into ballusta-tui-in-cli-2
martin-g Mar 2, 2026
0638969
Merge branch 'main' into ballusta-tui-in-cli-2
martin-g Mar 7, 2026
fc18d8a
Merge branch 'main' into ballusta-tui-in-cli-2
martin-g Mar 10, 2026
43367d2
Merge branch 'main' into ballusta-tui-in-cli-2
martin-g Mar 13, 2026
ec6aa45
Render the jobs main view
martin-g Mar 13, 2026
5cdedfb
Add search functionality to the Jobs and Metrics tables
martin-g Mar 13, 2026
c540633
Fix clippy
martin-g Mar 15, 2026
700e99a
Enable the help entry for the key binding for searching in metrics too
martin-g Mar 15, 2026
002297f
Extract the help overlay in its own module
martin-g Mar 15, 2026
5f5a79b
Remove some unused code for Jobs table styles
martin-g Mar 15, 2026
87f049c
Use a bounded channel for the TUI events handling
martin-g Mar 15, 2026
fa0e8d8
Preserve the table states in the App instance.
martin-g Mar 15, 2026
6a348ca
Merge branch 'main' into ballusta-tui-in-cli-2
martin-g Mar 15, 2026
1bec239
Use the job's start time to sort the jobs in the Jobs table
martin-g Mar 16, 2026
8203f6d
Merge branch 'main' into ballusta-tui-in-cli-2
martin-g Mar 16, 2026
8cb7d47
Merge branch 'main' into ballusta-tui-in-cli-2
martin-g Mar 16, 2026
593cec8
Show the DataFusion version in the header
martin-g Mar 16, 2026
05e9517
Use the new scheeduler_state::prometheus_support to show a better rea…
martin-g Mar 16, 2026
ad75c20
Show the full scheduler state in a popup (key binding: i)
martin-g Mar 16, 2026
94e8a26
Add support for sorting the Jobs table by status, % completed and sta…
martin-g Mar 16, 2026
a189b8e
chore(deps): bump lz4_flex from 0.12.0 to 0.12.1 in /python (#1514)
dependabot[bot] Mar 16, 2026
e9fd08d
chore(deps): bump github/codeql-action from 4.32.6 to 4.33.0 (#1515)
dependabot[bot] Mar 17, 2026
7ed4f2c
Implement cancelation of an active job (key binding: c)
martin-g Mar 17, 2026
4057669
Split domain.rs into several modules
martin-g Mar 17, 2026
d07d17e
Add a popup needed by the "cancel job" functionality
martin-g Mar 17, 2026
d38864c
Lower the visibility of App ::current_view and ::input_mode
martin-g Mar 17, 2026
967676c
Encapsulate the sending of events to App::send_event()
martin-g Mar 17, 2026
750c93a
Show the 'c' key binding only when there is a selected job
martin-g Mar 17, 2026
f3c9a00
Show the plans when a job is selected
martin-g Mar 17, 2026
49662a7
fmt
martin-g Mar 17, 2026
d963d51
chore(deps): bump rustls-webpki from 0.103.9 to 0.103.10 in /python (…
dependabot[bot] Mar 21, 2026
297997d
chore(deps): bump lz4_flex from 0.12.0 to 0.12.1 (#1518)
dependabot[bot] Mar 21, 2026
356b44b
chore(deps): bump github/codeql-action from 4.33.0 to 4.34.1 (#1519)
dependabot[bot] Mar 23, 2026
81976f6
chore(deps): bump rustls-webpki from 0.103.9 to 0.103.10 (#1521)
dependabot[bot] Mar 23, 2026
264c007
ci: pin third-party actions to Apache-approved SHAs (#1516)
kevinjqliu Mar 23, 2026
c99da56
Add basic rendering of completed job's dot graph
martin-g Mar 24, 2026
01ca704
Render the DOT graph as a directed graph (boxes and arrows)
martin-g Mar 24, 2026
e248431
Move the job_dot popup next to the Jobs UI modules
martin-g Mar 24, 2026
e0d5b88
Minor cleanups
martin-g Mar 24, 2026
f565b83
Improve the scrolling in the Jobs table
martin-g Mar 24, 2026
ca3632a
Fix the scrolling for the Metrics table
martin-g Mar 24, 2026
512eefd
Dynamically calculate the banner size
martin-g Mar 24, 2026
5293fa9
Merge branch 'main' into ballusta-tui-in-cli-2
martin-g Mar 24, 2026
c2551a3
Merge branch 'main' into ballusta-tui-in-cli-2
martin-g Mar 30, 2026
bb5c827
Merge branch 'main' into ballusta-tui-in-cli-2
martin-g Apr 3, 2026
480c6f1
Give some more space to the banner. The buttons width is dynamic anyway
martin-g Apr 3, 2026
b45c774
Show the job's plans in a popup
martin-g Apr 3, 2026
f91a513
Split the navigation bar in the footer into two lines
martin-g Apr 3, 2026
12e3967
Make bold the currently selected plan in the context navigation
martin-g Apr 3, 2026
973ff7a
Check for empty jobs/metrics before scrolling their tables
martin-g Apr 4, 2026
ec132b6
Fallback to HOME/.config/ and .config/ if dirs.config_dir() is not av…
martin-g Apr 4, 2026
7fbfc0d
Improve the docstring for init_file_logger()
martin-g Apr 4, 2026
07799cd
Fix the indentation for 'D' in the help popup
martin-g Apr 4, 2026
98b189a
Remove dead code
martin-g Apr 4, 2026
fdd4196
Use job.status instead of job.job_status
martin-g Apr 4, 2026
fc2b0d5
Add a check for 0 job.num_stages before calculating the percentage
martin-g Apr 4, 2026
b9861ef
Revert some unintentional changes after rename refactoring
martin-g Apr 4, 2026
f4099c9
fmt
martin-g Apr 4, 2026
fa5c75a
dotparser is needed only when 'tui' feature is enabled
martin-g Apr 4, 2026
bf4b008
Remove the rendering of the stage plan below the jobs table
martin-g Apr 4, 2026
f7871a2
Do not wrap the plans in the popup
martin-g Apr 4, 2026
94a8ccd
Optimize imports
martin-g Apr 4, 2026
c870503
Use saturating_add() when incrementing job_dot_scroll
martin-g Apr 4, 2026
122f049
url encode the job id when constructing the REST request url
martin-g Apr 4, 2026
623f1f8
Fix the scrollbar state in the jobs/metrics tables
martin-g Apr 4, 2026
ae2ce67
Use a special newtype struct for parsing the /api/metrics response
martin-g Apr 4, 2026
2bd3815
Use .clone() instead of .to_string()
martin-g Apr 4, 2026
ddb847f
Implement source() for TuiError
martin-g Apr 4, 2026
acda8ca
Simplify the logic for collecting the dis/enabled cargo features
martin-g Apr 4, 2026
a46e92c
Parallelize the HTTP requests in Dashboard
martin-g Apr 4, 2026
61b0220
Log a debug when an unexpected/unsupported type of event comes
martin-g Apr 4, 2026
d29a578
Cleanup
martin-g Apr 4, 2026
445bdbe
Simplify to avoid .clone()
martin-g Apr 4, 2026
d8db154
Rename Dashboard to Executors. Make Jobs the landing pahe
martin-g Apr 5, 2026
2af3733
Sort the metrics by name
martin-g Apr 5, 2026
3ca40e8
Render the executors in a Table widget
martin-g Apr 5, 2026
2d0185d
Add support for sorting by Metric's name
martin-g Apr 5, 2026
4da4d42
Add unit tests for the non-Ratatui functionality
martin-g Apr 5, 2026
ef66564
Add some more tests
martin-g Apr 5, 2026
4acb8fd
fmt
martin-g Apr 5, 2026
fa39e35
Merge branch 'main' into ballusta-tui-in-cli-2
martin-g Apr 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,356 changes: 1,226 additions & 130 deletions Cargo.lock

Large diffs are not rendered by default.

19 changes: 17 additions & 2 deletions ballista-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,29 @@ readme = "README.md"

[dependencies]
ballista = { path = "../ballista/client", version = "53.0.0", features = ["standalone"] }
chrono = { version = "0.4", default-features = false, features = ["std", "clock"], optional = true }
clap = { workspace = true, features = ["derive", "cargo"] }
config = { version = "0.15.19", default-features = false, features = ["yaml"], optional = true }
crossterm = { version = "0.29.0", features = ["event-stream"], optional = true }
datafusion = { workspace = true }
datafusion-cli = { workspace = true }
dirs = "6.0"
dotparser = { version = "0.3.0", optional = true }
env_logger = { workspace = true }
futures = { version = "0.3.31", optional = true }
mimalloc = { workspace = true }
percent-encoding = { version = "2.3.2", optional = true }
prometheus-parse = { version = "0.2", optional = true }
ratatui = { version = "0.30.0", optional = true }
reqwest = { version = "0.13.1", features = ["json"], optional = true }
rustyline = "17.0.1"
tokio = { workspace = true, features = ["macros", "rt", "rt-multi-thread", "sync", "parking_lot"] }
serde = { version = "1", features = ["derive"], optional = true }
serde_json = { version = "1", optional = true }
tokio = { workspace = true, features = ["macros", "rt", "rt-multi-thread", "sync", "time", "parking_lot"] }
tracing = { version = "0.1", optional = true }
tracing-appender = { version = "0.2", optional = true }
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"], optional = true }
tui-big-text = { version = "0.8.2", optional = true }

[features]

tui = ["dep:chrono", "dep:config", "dep:crossterm", "dep:dotparser", "dep:futures", "dep:percent-encoding", "dep:prometheus-parse", "dep:ratatui", "dep:reqwest", "dep:serde", "dep:serde_json", "dep:tracing", "dep:tracing-subscriber", "dep:tracing-appender", "dep:tui-big-text"]
21 changes: 18 additions & 3 deletions ballista-cli/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ pub enum Command {
SearchFunctions(String),
QuietMode(Option<bool>),
OutputFormat(Option<String>),
#[cfg(feature = "tui")]
OpenTui,
}

pub enum OutputFormat {
Expand Down Expand Up @@ -129,11 +131,18 @@ impl Command {
"Unexpected change output format, this should be handled outside"
.to_string(),
)),
#[cfg(feature = "tui")]
Self::OpenTui => match crate::tui::tui_main().await {
Ok(()) => Ok(()),
Err(e) => Err(DataFusionError::Internal(format!(
"Error opening TUI: {e}",
))),
},
}
}

fn get_name_and_description(&self) -> (&'static str, &'static str) {
match self {
match *self {
Self::Quit => ("\\q", "quit ballista-cli"),
Self::ListTables => ("\\d", "list tables"),
Self::DescribeTable(_) => ("\\d name", "describe table"),
Expand All @@ -144,11 +153,13 @@ impl Command {
Self::OutputFormat(_) => {
("\\pset [NAME [VALUE]]", "set table output option\n(format)")
}
#[cfg(feature = "tui")]
Self::OpenTui => ("\\tui", "open tui"),
}
}
}

const ALL_COMMANDS: [Command; 8] = [
const ALL_COMMANDS: &[Command] = &[
Command::ListTables,
Command::DescribeTable(String::new()),
Command::Quit,
Expand All @@ -157,6 +168,8 @@ const ALL_COMMANDS: [Command; 8] = [
Command::SearchFunctions(String::new()),
Command::QuietMode(None),
Command::OutputFormat(None),
#[cfg(feature = "tui")]
Command::OpenTui,
];

fn all_commands_info() -> RecordBatch {
Expand All @@ -165,7 +178,7 @@ fn all_commands_info() -> RecordBatch {
Field::new("Description", DataType::Utf8, false),
]));
let (names, description): (Vec<&str>, Vec<&str>) = ALL_COMMANDS
.into_iter()
.iter()
.map(|c| c.get_name_and_description())
.unzip();
RecordBatch::try_new(
Expand Down Expand Up @@ -205,6 +218,8 @@ impl FromStr for Command {
Self::OutputFormat(Some(subcommand.to_string()))
}
("pset", None) => Self::OutputFormat(None),
#[cfg(feature = "tui")]
("tui", None) => Self::OpenTui,
_ => return Err(()),
})
}
Expand Down
2 changes: 2 additions & 0 deletions ballista-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@ pub const BALLISTA_CLI_VERSION: &str = env!("CARGO_PKG_VERSION");

pub mod command;
pub mod exec;
#[cfg(feature = "tui")]
mod tui;

pub use datafusion_cli::{functions, helper, print_format, print_options};
21 changes: 17 additions & 4 deletions ballista-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
// specific language governing permissions and limitations
// under the License.

#[cfg(feature = "tui")]
mod tui;

use std::path::Path;
use std::{env, sync::Arc};

Expand All @@ -24,7 +27,6 @@ use ballista_cli::{
};
use clap::Parser;
use datafusion::{
common::Result,
execution::SessionStateBuilder,
prelude::{SessionConfig, SessionContext},
};
Expand Down Expand Up @@ -99,20 +101,31 @@ struct Args {

#[clap(long, help = "Enables console syntax highlighting")]
color: bool,

#[cfg(feature = "tui")]
#[clap(long, help = "Enables terminal user interface")]
tui: bool,
}

#[tokio::main]
pub async fn main() -> Result<()> {
env_logger::init();
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let args = Args::parse();

#[cfg(feature = "tui")]
if args.tui {
return tui::tui_main()
.await
.map_err(|e| Box::new(e) as Box<dyn std::error::Error>);
}
env_logger::init();

if !args.quiet {
println!("Ballista CLI v{BALLISTA_CLI_VERSION}");
}

if let Some(ref path) = args.data_path {
let p = Path::new(path);
env::set_current_dir(p).unwrap();
env::set_current_dir(p)?;
};

let mut ballista_config =
Expand Down
Loading
Loading