datafusion_dft/tui/ui/tabs/
sql.rs1use ratatui::{
19 buffer::Buffer,
20 layout::{Alignment, Constraint, Direction, Layout, Rect},
21 style::{palette::tailwind, Style, Stylize},
22 text::Span,
23 widgets::{block::Title, Block, Borders, Paragraph, Row, StatefulWidget, Table, Widget, Wrap},
24};
25
26use crate::tui::App;
27use crate::tui::{state::tabs::sql::SQLTabMode, ui::convert::record_batches_to_table};
28
29pub fn render_sql_editor(area: Rect, buf: &mut Buffer, app: &App) {
30 let sql_tab = &app.state.sql_tab;
31 let border_color = if app.state.sql_tab.editor_editable() {
32 tailwind::ORANGE.c500
33 } else {
34 tailwind::WHITE
35 };
36 let title = if sql_tab.ddl_error() {
37 vec![
38 Span::from(" Editor ").fg(tailwind::WHITE),
39 Span::from("(DDL Error) ").red(),
40 ]
41 } else {
42 vec![Span::from(" Editor ").fg(tailwind::WHITE)]
43 };
44 let mode_text = format!(" {:?} ", sql_tab.mode());
45 let mode = Title::from(mode_text.as_str()).alignment(Alignment::Right);
46 let block = Block::default()
47 .title(title)
48 .title(mode)
49 .borders(Borders::ALL)
50 .fg(border_color);
51 let mut editor = app.state.sql_tab.active_editor_cloned();
52 editor.set_style(Style::default().fg(tailwind::WHITE));
53 editor.set_block(block);
54 editor.render(area, buf)
55}
56
57pub fn render_sql_results(area: Rect, buf: &mut Buffer, app: &App) {
58 let sql_tab = &app.state.sql_tab;
60 match (
61 sql_tab.current_batch(),
62 sql_tab.current_page(),
63 sql_tab.query_results_state(),
64 sql_tab.execution_error(),
65 ) {
66 (Some(batch), Some(p), Some(s), None) => {
67 let block = Block::default()
68 .title(" Results ")
69 .borders(Borders::ALL)
70 .title(Title::from(format!(" Page {p} ")).alignment(Alignment::Right));
71 let batches = vec![batch];
72 let maybe_table = record_batches_to_table(&batches);
73
74 let block = block.title_bottom("Stats").fg(tailwind::ORANGE.c500);
75 match maybe_table {
76 Ok(table) => {
77 let table = table
78 .highlight_style(Style::default().bg(tailwind::WHITE).fg(tailwind::BLACK))
79 .block(block);
80
81 let mut s = s.borrow_mut();
82 StatefulWidget::render(table, area, buf, &mut s);
83 }
84 Err(e) => {
85 let row = Row::new(vec![e.to_string()]);
86 let widths = vec![Constraint::Percentage(100)];
87 let table = Table::new(vec![row], widths).block(block);
88 Widget::render(table, area, buf);
89 }
90 }
91 }
92 (_, _, _, Some(e)) => {
93 let dur = e.duration().as_millis();
94 let block = Block::default()
95 .title(" Results ")
96 .borders(Borders::ALL)
97 .title(Title::from(" Page ").alignment(Alignment::Right))
98 .title_bottom(format!(" {}ms ", dur));
99 let p = Paragraph::new(e.error().to_string())
100 .block(block)
101 .wrap(Wrap { trim: true });
102 Widget::render(p, area, buf);
103 }
104 _ => {
105 let block = Block::default()
106 .title(" Results ")
107 .borders(Borders::ALL)
108 .title(Title::from(" Page ").alignment(Alignment::Right));
109 let row = Row::new(vec!["Run a query to generate results"]);
110 let widths = vec![Constraint::Percentage(100)];
111 let table = Table::new(vec![row], widths).block(block);
112 Widget::render(table, area, buf);
113 }
114 }
115}
116
117pub fn render_sql_help(area: Rect, buf: &mut Buffer, app: &App) {
118 let block = Block::default();
119
120 let help = match app.state.sql_tab.mode() {
121 SQLTabMode::Normal => {
122 if app.state.sql_tab.editor_editable() {
123 vec!["'Esc' to exit edit mode"]
124 } else {
125 vec![
126 "'e' to edit",
127 "'c' to clear editor",
128 "'d' for DDL mode",
129 "'q' to exit app",
130 "'Enter' to run query",
131 ]
132 }
133 }
134 SQLTabMode::DDL => {
135 if app.state.sql_tab.editor_editable() {
136 vec!["'Esc' to exit edit mode"]
137 } else {
138 vec![
139 "'e' to edit",
140 "'c' to clear editor",
141 "'n' for Normal mode",
142 "'s' to save DDL",
143 "'Enter' to run DDL",
144 ]
145 }
146 }
147 };
148
149 let help_text = help.join(" | ");
150 let p = Paragraph::new(help_text)
151 .block(block)
152 .alignment(Alignment::Center);
153 p.render(area, buf);
154}
155
156pub fn render_sql(area: Rect, buf: &mut Buffer, app: &App) {
157 let mode = app.state.sql_tab.mode();
158
159 match mode {
160 SQLTabMode::Normal => {
161 let constraints = vec![
162 Constraint::Fill(1),
163 Constraint::Fill(1),
164 Constraint::Length(1),
165 ];
166 let [editor_area, results_area, help_area] =
167 Layout::new(Direction::Vertical, constraints).areas(area);
168
169 render_sql_editor(editor_area, buf, app);
170 render_sql_results(results_area, buf, app);
171 render_sql_help(help_area, buf, app);
172 }
173 SQLTabMode::DDL => {
174 let constraints = vec![Constraint::Fill(1), Constraint::Length(1)];
175 let [editor_area, help_area] =
176 Layout::new(Direction::Vertical, constraints).areas(area);
177
178 render_sql_editor(editor_area, buf, app);
179 render_sql_help(help_area, buf, app);
180 }
181 };
182}