Skip to content

Commit e6d1873

Browse files
committed
Refactoring: Reuse shared code in tables
* Group duplicated code for tables in one module and use them for both logs and search tables. * Other refactoring are postponed for now until filters are implemented.
1 parent c848ea8 commit e6d1873

File tree

4 files changed

+211
-191
lines changed

4 files changed

+211
-191
lines changed

application/apps/indexer/gui/application/src/session/ui/bottom_panel/search/search_table.rs

Lines changed: 58 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,23 @@
1-
use std::{ops::Range, rc::Rc, sync::mpsc::Receiver as StdReceiver, time::Duration};
1+
use std::{ops::Range, rc::Rc, sync::mpsc::Receiver as StdReceiver};
22

3-
use egui::{Color32, Frame, Id, Label, Margin, Sense, Shape, Stroke, Ui, Widget, vec2};
4-
use egui_table::{AutoSizeMode, CellInfo, Column, PrefetchInfo, TableDelegate};
3+
use egui::{Color32, Label, Sense, Ui, Widget};
4+
use egui_table::{CellInfo, Column, PrefetchInfo, TableDelegate};
55
use stypes::{GrabbedElement, NearestPosition};
66
use tokio::sync::mpsc::Sender;
77

88
use crate::{
9-
host::{notification::AppNotification, ui::UiActions},
9+
host::ui::UiActions,
1010
session::{
1111
command::SessionCommand,
1212
error::SessionError,
1313
ui::{
14-
common::logs_mapped::LogsMapped,
14+
common::{self, logs_mapped::LogsMapped, logs_tables::grab_cmd_consts},
1515
definitions::{LogTableItem, schema::LogSchema},
16-
shared::{ObserveState, SessionShared},
16+
shared::SessionShared,
1717
},
1818
},
1919
};
2020

21-
const TIMEOUT_DURATION: Duration = Duration::from_millis(50);
22-
const SEND_INTERVAL: Duration = Duration::from_millis(5);
23-
const SEND_RETRY_MAX_COUNT: u8 = 10;
24-
2521
#[derive(Debug)]
2622
pub struct SearchTable {
2723
cmd_tx: Sender<SessionCommand>,
@@ -38,19 +34,15 @@ pub struct SearchTable {
3834

3935
impl SearchTable {
4036
pub fn new(cmd_tx: Sender<SessionCommand>, schema: Rc<dyn LogSchema>) -> Self {
41-
let mut cols = Vec::with_capacity(schema.columns().len() + 1);
42-
let nums_col = Column::new(100.0).range(50.0..=500.0).resizable(true);
43-
44-
cols.push(nums_col);
45-
cols.extend(schema.columns().iter().map(|col| col.column));
37+
let columns = common::logs_tables::create_table_columns(schema.as_ref());
4638

4739
Self {
4840
cmd_tx,
4941
last_visible_rows: None,
5042
indexed_logs: LogsMapped::new(schema),
5143
pending_logs_rx: None,
5244
scroll_nearest_pos: None,
53-
columns: cols.into_boxed_slice(),
45+
columns,
5446
}
5547
}
5648

@@ -64,14 +56,11 @@ impl SearchTable {
6456
actions: &mut UiActions,
6557
ui: &mut Ui,
6658
) {
67-
let id_salt = Id::new("search_table");
68-
6959
let mut table = egui_table::Table::new()
70-
.id_salt(id_salt)
60+
.id_salt("search_table")
7161
.num_rows(shared.search.total_count())
7262
.headers(Vec::new())
7363
.columns(self.columns.as_ref())
74-
.auto_size_mode(AutoSizeMode::Never)
7564
.num_sticky_cols(1);
7665

7766
if let Some(row_nr) = self.scroll_nearest_pos.take().map(|pos| pos.index)
@@ -166,79 +155,58 @@ impl<'a> LogsDelegate<'a> {
166155
}
167156

168157
fn render_row_header(&mut self, ui: &mut Ui, cell: &CellInfo) {
169-
ui.horizontal(|ui| {
170-
let (res, painter) =
171-
//TODO AAZ: Use central positions for magic values in all tables like the 5.0 here.
172-
ui.allocate_painter(vec2(5.0, ui.available_height()), Sense::hover());
173-
174-
let has_multi_sources = self.has_multi_sources;
175-
let log_item = self.get_log_item(cell);
176-
if has_multi_sources && let Some(log_item) = log_item {
177-
let source_idx = log_item.element.source_id;
178-
let color = ObserveState::source_color(source_idx as usize);
179-
painter.rect_filled(res.rect, 0, color);
180-
}
158+
let (text, color_idx) = self
159+
.get_log_item(cell)
160+
.map(|item| {
161+
(
162+
item.element.pos.to_string(),
163+
self.has_multi_sources
164+
.then_some(item.element.source_id as usize),
165+
)
166+
})
167+
.unwrap_or_default();
181168

182-
ui.label(
183-
log_item
184-
.map(|i| i.element.pos.to_string())
185-
.unwrap_or_default(),
186-
);
187-
});
169+
common::logs_tables::render_row_header(ui, text, color_idx);
188170
}
189171

190172
fn render_log_cell(&mut self, ui: &mut Ui, cell: &CellInfo) {
191173
let mut source_changed = false;
192174

193-
Frame::NONE
194-
.inner_margin(Margin::symmetric(4, 0))
195-
.show(ui, |ui| {
196-
let log_item = match self.get_log_item(cell) {
197-
Some(log) => log,
198-
None => {
199-
// Ensure data will be requested on next frame.
200-
if self.table.pending_logs_rx.is_none() {
201-
self.table.last_visible_rows = None;
202-
}
203-
204-
ui.label("Loading...");
205-
return;
175+
common::logs_tables::get_cell_frame().show(ui, |ui| {
176+
let log_item = match self.get_log_item(cell) {
177+
Some(log) => log,
178+
None => {
179+
// Ensure data will be requested on next frame.
180+
if self.table.pending_logs_rx.is_none() {
181+
self.table.last_visible_rows = None;
206182
}
207-
};
208183

209-
source_changed = self.has_multi_sources
210-
&& self
211-
.table
212-
.indexed_logs
213-
.source_change_positions()
214-
.contains(&log_item.element.pos);
215-
216-
let content = log_item
217-
.column_ranges
218-
.get(cell.col_nr.saturating_sub(1))
219-
.and_then(|rng| log_item.element.content.get(rng.to_owned()))
220-
.unwrap_or_default();
221-
222-
if Label::new(content).ui(ui).clicked() {
223-
let is_selected = self.is_row_selected(Some(log_item));
224-
self.toggle_row_selected(log_item.element.pos as u64, is_selected);
184+
ui.label("Loading...");
185+
return;
225186
}
226-
});
187+
};
188+
189+
source_changed = self.has_multi_sources
190+
&& self
191+
.table
192+
.indexed_logs
193+
.source_change_positions()
194+
.contains(&log_item.element.pos);
195+
196+
let content = log_item
197+
.column_ranges
198+
.get(cell.col_nr.saturating_sub(1))
199+
.and_then(|rng| log_item.element.content.get(rng.to_owned()))
200+
.unwrap_or_default();
201+
202+
if Label::new(content).ui(ui).clicked() {
203+
let is_selected = self.is_row_selected(Some(log_item));
204+
self.toggle_row_selected(log_item.element.pos as u64, is_selected);
205+
}
206+
});
227207

228208
if source_changed {
229-
let rect = ui.max_rect();
230-
ui.painter().add(Shape::dashed_line(
231-
&[
232-
egui::Pos2::new(rect.min.x, rect.top() + 1.0),
233-
egui::Pos2::new(rect.max.x, rect.top() + 1.0),
234-
],
235-
Stroke::new(
236-
0.5,
237-
ui.style().visuals.widgets.noninteractive.fg_stroke.color,
238-
),
239-
4.0,
240-
2.0,
241-
));
209+
common::logs_tables::render_upper_bound(ui);
242210
}
243211
}
244212
}
@@ -282,16 +250,16 @@ impl TableDelegate for LogsDelegate<'_> {
282250
if !self.actions.send_command_with_retry(
283251
&self.table.cmd_tx,
284252
cmd,
285-
SEND_INTERVAL,
286-
SEND_RETRY_MAX_COUNT,
253+
grab_cmd_consts::SEND_INTERVAL,
254+
grab_cmd_consts::SEND_RETRY_MAX_COUNT,
287255
) {
288256
return;
289257
}
290258

291259
elems_rx
292260
};
293261

294-
if let Ok(elements) = logs_rx.recv_timeout(TIMEOUT_DURATION) {
262+
if let Ok(elements) = logs_rx.recv_timeout(grab_cmd_consts::TIMEOUT_DURATION) {
295263
match elements {
296264
Ok(elements) => {
297265
let combined = rng.zip(elements);
@@ -300,12 +268,11 @@ impl TableDelegate for LogsDelegate<'_> {
300268
.append(combined, self.has_multi_sources);
301269
}
302270
Err(error) => {
303-
let session_id = self.shared.get_id();
304-
log::error!("Session Error: Session ID: {session_id}, error: {error}");
305-
306-
let notifi = AppNotification::SessionError { session_id, error };
307-
308-
self.actions.add_notification(notifi);
271+
common::logs_tables::handle_grab_errors(
272+
error,
273+
self.shared.get_id(),
274+
self.actions,
275+
);
309276
}
310277
}
311278
} else {
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//! Provides shared helper functions and utilities to be used
2+
//! with logs tables (both logs and search tables).
3+
4+
use egui::{Frame, Margin, Sense, Shape, Stroke, Ui, vec2};
5+
use egui_table::Column;
6+
use uuid::Uuid;
7+
8+
use crate::{
9+
host::{notification::AppNotification, ui::UiActions},
10+
session::{
11+
error::SessionError,
12+
ui::{definitions::schema::LogSchema, shared::ObserveState},
13+
},
14+
};
15+
16+
/// Constants needed when sending grab logs commands.
17+
pub mod grab_cmd_consts {
18+
use std::time::Duration;
19+
20+
pub const TIMEOUT_DURATION: Duration = Duration::from_millis(50);
21+
pub const SEND_INTERVAL: Duration = Duration::from_millis(5);
22+
pub const SEND_RETRY_MAX_COUNT: u8 = 10;
23+
}
24+
25+
/// Creates the columns for logs table based on the provided `schema`,
26+
/// inserting the row header column into them.
27+
pub fn create_table_columns(schema: &dyn LogSchema) -> Box<[Column]> {
28+
let mut columns = Vec::with_capacity(schema.columns().len() + 1);
29+
let row_header_col = Column::new(100.0).range(50.0..=500.0).resizable(true);
30+
31+
columns.push(row_header_col);
32+
columns.extend(schema.columns().iter().map(|col| col.column));
33+
34+
columns.into_boxed_slice()
35+
}
36+
37+
/// Draw border line on the top of a log cell indicating that its
38+
/// source is different from the log above it.
39+
pub fn render_upper_bound(ui: &mut Ui) {
40+
let rect = ui.max_rect();
41+
// Draw dashed line at the top of the cell
42+
ui.painter().add(Shape::dashed_line(
43+
&[
44+
egui::Pos2::new(rect.min.x, rect.top() + 1.0),
45+
egui::Pos2::new(rect.max.x, rect.top() + 1.0),
46+
],
47+
Stroke::new(
48+
0.5,
49+
ui.style().visuals.widgets.noninteractive.fg_stroke.color,
50+
),
51+
4.0,
52+
2.0,
53+
));
54+
}
55+
56+
/// Render the row header cell in log tables, display the text and the source color
57+
/// when `color_idx` is provided.
58+
pub fn render_row_header(ui: &mut Ui, text: String, color_idx: Option<usize>) {
59+
ui.horizontal(|ui| {
60+
let (res, painter) = ui.allocate_painter(vec2(5.0, ui.available_height()), Sense::hover());
61+
62+
if let Some(color_idx) = color_idx {
63+
let color = ObserveState::source_color(color_idx);
64+
painter.rect_filled(res.rect, 0.0, color);
65+
}
66+
67+
ui.label(text);
68+
});
69+
}
70+
71+
/// Frame for table content cells.
72+
pub fn get_cell_frame() -> Frame {
73+
Frame::NONE.inner_margin(Margin::symmetric(4, 0))
74+
}
75+
76+
pub fn handle_grab_errors(error: SessionError, session_id: Uuid, actions: &mut UiActions) {
77+
log::error!("Session Error: Session ID: {session_id}, error: {error}");
78+
79+
let notifi = AppNotification::SessionError { session_id, error };
80+
81+
actions.add_notification(notifi);
82+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
pub mod logs_mapped;
2+
pub mod logs_tables;

0 commit comments

Comments
 (0)