Skip to content

Commit 0e5efbc

Browse files
committed
Allow filtering by number and bool
1 parent 9a5f86e commit 0e5efbc

File tree

3 files changed

+33
-14
lines changed

3 files changed

+33
-14
lines changed

src/array_table.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ type ColumnFilterCache = egui::util::cache::FrameCache<IndexSet<String>, CacheA>
189189
impl egui::util::cache::ComputerMut<(&Column, &Vec<JsonArrayEntries<String>>, &String), IndexSet<String>> for CacheA {
190190
fn compute(&mut self, (column, nodes, parent_pointer): (&Column, &Vec<JsonArrayEntries<String>>, &String)) -> IndexSet<String> {
191191
let mut unique_values = IndexSet::new();
192-
if matches!(column.value_type, ValueType::String) {
192+
if ArrayTable::is_filterable(column) {
193193
nodes.iter().enumerate().map(|(i, row)| {
194194
ArrayTable::get_pointer_for_column(parent_pointer, &&row.entries, i, column).filter(|entry| entry.value.is_some()).map(|entry| entry.value.clone().unwrap())
195195
}).for_each(|value| {
@@ -198,7 +198,22 @@ impl egui::util::cache::ComputerMut<(&Column, &Vec<JsonArrayEntries<String>>, &S
198198
}
199199
})
200200
}
201-
unique_values.sort_by(|a, b| a.cmp(b));
201+
if matches!(column.value_type, ValueType::Number) {
202+
unique_values.sort_by(|a, b| {
203+
let num_a = a.parse::<f64>();
204+
let num_b = b.parse::<f64>();
205+
206+
// Compare parsed numbers; handle parse errors by pushing them to the end
207+
match (num_a, num_b) {
208+
(Ok(a), Ok(b)) => a.partial_cmp(&b).unwrap_or(std::cmp::Ordering::Equal),
209+
(Ok(_), Err(_)) => std::cmp::Ordering::Less, // Numbers are less than errors
210+
(Err(_), Ok(_)) => std::cmp::Ordering::Greater, // Errors are greater than numbers
211+
(Err(_), Err(_)) => std::cmp::Ordering::Equal, // Treat errors equally
212+
}
213+
});
214+
} else {
215+
unique_values.sort_by(|a, b| a.cmp(b));
216+
}
202217
unique_values
203218
}
204219
}
@@ -416,14 +431,14 @@ impl ArrayTable {
416431
if column.name.eq("") {
417432
return;
418433
}
419-
let response = icon::button(ui, THUMBTACK, if pinned_column_table { "Unpin column" } else { "Pin column to left" });
434+
let response = icon::button(ui, THUMBTACK, Some(if pinned_column_table { "Unpin column" } else { "Pin column to left" }), None);
420435
if response.clicked() {
421436
pinned_column = Some(index);
422437
}
423438
let column_id = Id::new(&name);
424439
let checked_filtered_values = self.columns_filter.get(&column.name);
425440
PopupMenu::new(column_id.with("filter"))
426-
.show_ui(ui, |ui| icon::button_with_color(ui, FILTER, "Filter column by", if checked_filtered_values.is_some() { Some(ACTIVE_COLOR) } else { None }),
441+
.show_ui(ui, |ui| icon::button(ui, FILTER, None, if checked_filtered_values.is_some() { Some(ACTIVE_COLOR) } else { None }),
427442
|ui| {
428443
let mut chcked = if let Some(filters) = checked_filtered_values {
429444
filters.contains(&NON_NULL_FILTER_VALUE.to_owned())
@@ -434,7 +449,7 @@ impl ArrayTable {
434449
clicked_filter_non_null_column = Some(name);
435450
}
436451

437-
if matches!(column.value_type, ValueType::String) {
452+
if Self::is_filterable(column) {
438453
let values = ui.memory_mut(|mem| {
439454
let cache = mem.caches.cache::<ColumnFilterCache>();
440455

@@ -672,6 +687,11 @@ impl ArrayTable {
672687
array_response
673688
}
674689

690+
#[inline]
691+
fn is_filterable(column: &Column) -> bool {
692+
!(matches!(column.value_type, ValueType::Object(_)) || matches!(column.value_type, ValueType::Array(_)) || matches!(column.value_type, ValueType::Null))
693+
}
694+
675695
fn open_subtable(row_index: usize, entry: &FlatJsonValue<String>, content: String) -> Option<SubTable> {
676696
// if matches!(entry.pointer.value_type, ValueType::Object(false)) {
677697
// let options = ParseOptions::default().parse_array(true).keep_object_raw_data(false).start_parse_at(entry.pointer.pointer.clone())

src/components/icon.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,16 @@ pub fn icon(name: &'static str) -> egui::RichText {
77
.size(12.0)
88
}
99

10-
pub fn button(ui: &mut Ui, name: &'static str, tooltip: &str) -> Response {
11-
let button = Button::new(icon::icon(name));
12-
13-
ui.add(button).on_hover_ui(|ui| { ui.label(tooltip); } )
14-
}
15-
pub fn button_with_color(ui: &mut Ui, name: &'static str, tooltip: &str, color: Option<Color32>) -> Response {
10+
pub fn button(ui: &mut Ui, name: &'static str, tooltip: Option<&str>, color: Option<Color32>) -> Response {
1611
let mut icon = icon::icon(name);
1712
if color.is_some() {
1813
icon = icon.color(color.unwrap());
1914
}
2015
let button = Button::new(icon);
16+
let mut response = ui.add(button);
17+
if let Some(tooltip) = tooltip {
18+
response = response.on_hover_ui(|ui| { ui.label(tooltip); } );
19+
}
2120

22-
ui.add(button).on_hover_ui(|ui| { ui.label(tooltip); } )
21+
response
2322
}

src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,8 +321,8 @@ impl eframe::App for MyApp {
321321
let text_edit = TextEdit::singleline(&mut table.scroll_to_row).hint_text(hint_text);
322322
let scroll_to_row_response = ui.add(text_edit);
323323
if !table.matching_rows.is_empty() {
324-
let response_prev = icon::button(ui, CHEVRON_UP, "Previous occurrence");
325-
let response_next = icon::button(ui, CHEVRON_DOWN, "Next occurrence");
324+
let response_prev = icon::button(ui, CHEVRON_UP, Some("Previous occurrence"), None);
325+
let response_next = icon::button(ui, CHEVRON_DOWN, Some("Next occurrence"), None);
326326
ui.label(RichText::new(format!("{}/{}", table.matching_row_selected + 1, table.matching_rows.len())));
327327

328328
if response_prev.clicked() {

0 commit comments

Comments
 (0)