Skip to content

Commit 1d39bd5

Browse files
committed
feat: add row numbers to rows
1 parent 39407a6 commit 1d39bd5

10 files changed

+304
-29
lines changed

src/app.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ pub struct LogViewerApp {
2929
track_item_align: Option<Align>,
3030
shortcuts: Shortcuts,
3131
auto_scroll_to_end: bool,
32+
// TODO 4: Add UI to set / unset field
33+
/// When set adds a field with this name and populates it with the row numbers
34+
pub row_idx_field_name: Option<String>,
3235

3336
#[serde(skip)]
3437
should_focus_search: bool,
@@ -49,6 +52,7 @@ impl Default for LogViewerApp {
4952
track_item_align: Default::default(),
5053
shortcuts: Default::default(),
5154
auto_scroll_to_end: Default::default(),
55+
row_idx_field_name: Some("row#".to_string()),
5256
should_focus_search: Default::default(),
5357
should_scroll: Default::default(),
5458
show_last_filename: true,
@@ -296,20 +300,21 @@ impl LogViewerApp {
296300
ui.colored_label(ui.visuals().error_fg_color, msg);
297301
}
298302
LoadingStatus::Success(data) => {
299-
self.loading_status = match Data::try_from(&data[..]) {
300-
Ok(mut data) => {
301-
if let Some(old_data) = self.data.as_mut() {
302-
// Preserve filter across loads of the data
303-
data.filter = old_data.filter.take();
304-
}
305-
self.data = Some(data);
306-
if self.auto_scroll_to_end {
307-
self.move_selected_last();
303+
self.loading_status =
304+
match Data::try_from((self.row_idx_field_name.as_ref(), &data[..])) {
305+
Ok(mut data) => {
306+
if let Some(old_data) = self.data.as_mut() {
307+
// Preserve filter settings across loads of the data
308+
data.filter = old_data.filter.take();
309+
}
310+
self.data = Some(data);
311+
if self.auto_scroll_to_end {
312+
self.move_selected_last();
313+
}
314+
LoadingStatus::NotInProgress
308315
}
309-
LoadingStatus::NotInProgress
316+
Err(e) => LoadingStatus::Failed(format!("{e:?}")),
310317
}
311-
Err(e) => LoadingStatus::Failed(format!("{e:?}")),
312-
}
313318
}
314319
}
315320
}

src/app/data.rs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@ use anyhow::Context;
77
use data_iter::DataIter;
88
use filter::{FieldSpecifier, FilterConfig};
99
use log::warn;
10+
use serde_json::Value;
1011

1112
use super::calculate_hash;
1213
mod data_iter;
1314
pub mod filter;
1415

16+
type LogRowIdxFieldName<'a> = Option<&'a String>;
17+
1518
#[derive(serde::Deserialize, serde::Serialize, Default, Debug, PartialEq, Eq)]
1619
#[serde(default)]
1720
pub struct Data {
@@ -30,7 +33,6 @@ pub struct LogRow {
3033

3134
#[derive(Default, Debug, PartialEq, Eq, Clone)]
3235
struct CachedDisplayInfo {
33-
// TODO 1: Add row numbers to top section (optionally)
3436
data: Vec<(String, String)>,
3537
common_fields_hash: u64,
3638
}
@@ -122,6 +124,11 @@ impl LogRow {
122124
});
123125
}
124126
}
127+
128+
/// Adds the value passed at the key if the key does not exist
129+
fn or_insert(&mut self, key: String, value: Value) {
130+
self.data.entry(key).or_insert(value);
131+
}
125132
}
126133

127134
impl Data {
@@ -283,25 +290,33 @@ fn is_included(
283290
}
284291
}
285292

286-
impl TryFrom<&str> for LogRow {
293+
impl TryFrom<(LogRowIdxFieldName<'_>, usize, &str)> for LogRow {
287294
type Error = anyhow::Error;
288295

289-
fn try_from(value: &str) -> Result<Self, Self::Error> {
290-
Ok(Self {
296+
fn try_from(
297+
(log_row_idx_key, row_idx_val, value): (LogRowIdxFieldName<'_>, usize, &str),
298+
) -> Result<Self, Self::Error> {
299+
let mut result = Self {
291300
data: serde_json::from_str(value)?,
292301
cached_display_list: None,
293-
})
302+
};
303+
if let Some(key) = log_row_idx_key {
304+
result.or_insert(key.to_string(), row_idx_val.into());
305+
}
306+
Ok(result)
294307
}
295308
}
296309

297-
impl TryFrom<&str> for Data {
310+
impl TryFrom<(LogRowIdxFieldName<'_>, &str)> for Data {
298311
type Error = anyhow::Error;
299312

300-
fn try_from(value: &str) -> Result<Self, Self::Error> {
313+
fn try_from(
314+
(log_row_idx_key, value): (LogRowIdxFieldName<'_>, &str),
315+
) -> Result<Self, Self::Error> {
301316
let mut result = Data::default();
302317
for (i, line) in value.lines().enumerate() {
303318
result.rows.push(
304-
LogRow::try_from(line)
319+
LogRow::try_from((log_row_idx_key, i, line))
305320
.with_context(|| format!("failed to parse line {}", i + 1))?,
306321
);
307322
}

src/app/data/tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub(crate) fn insta_settings() -> insta::Settings {
3636
fn deserialize_rows_from_string(insta_settings: insta::Settings) {
3737
glob!(PATH_PROJECT_ROOT, PATH_TEST_SAMPLES, |path| {
3838
let input = std::fs::read_to_string(path).unwrap();
39-
let data = Data::try_from(&input[..]).unwrap();
39+
let data = Data::try_from((Some(&"Test Row#".to_string()), &input[..])).unwrap();
4040
let log_filename = path.file_name().unwrap().to_string_lossy().to_string();
4141
insta_settings.bind(|| insta::assert_ron_snapshot!(format!("{log_filename}_ron"), data));
4242
insta_settings.bind(|| insta::assert_yaml_snapshot!(format!("{log_filename}_yaml"), data));
@@ -58,7 +58,7 @@ fn round_trip_from_samples(#[case] serde_format: SerdeFormat) {
5858

5959
glob!(PATH_PROJECT_ROOT, PATH_TEST_SAMPLES, |path| {
6060
let input = std::fs::read_to_string(path).unwrap();
61-
let rows_before = Data::try_from(&input[..]).unwrap();
61+
let rows_before = Data::try_from((Some(&"Test Row#".to_string()), &input[..])).unwrap();
6262

6363
// Test individual rows
6464
for (i, row_before) in rows_before.rows_iter().enumerate() {

src/app/data_display_options.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ impl Default for DataDisplayOptions {
2929
fn default() -> Self {
3030
Self {
3131
// TODO 3: Add ability to show, select and reorder selected fields
32-
main_list_fields: ["time", "request_id", "otel.name", "msg"]
32+
main_list_fields: ["row#", "time", "request_id", "otel.name", "msg"]
3333
.into_iter()
3434
.map(String::from)
3535
.collect(),

0 commit comments

Comments
 (0)