more grouping prep

This commit is contained in:
Robin Appelman 2025-08-10 12:35:23 +02:00
commit 0fa90510cb
14 changed files with 251 additions and 185 deletions

View file

@ -1,4 +1,4 @@
use crate::app::{App, Filter};
use crate::app::Filter;
use crate::logfile::logline::{format_time, LogLine};
use crate::ui::state::GroupedLogGrouping;
use crate::ui::style::TABLE_HEADER_STYLE;
@ -10,28 +10,25 @@ use ratatui::prelude::{StatefulWidget, Widget};
use ratatui::text::Text;
use ratatui::widgets::{Cell, Paragraph, Row, Wrap};
pub struct GroupedLogs<'a> {
pub struct LogsByIdentifier<'a> {
lines: &'a [&'a LogLine<'a>],
app: &'a App<'a>,
filter: &'a Filter,
grouping: GroupedLogGrouping,
}
pub fn grouped_logs<'a>(
app: &'a App<'a>,
pub fn logs_by_identifier<'a>(
lines: &'a [&'a LogLine<'a>],
filter: &'a Filter,
grouping: GroupedLogGrouping,
) -> GroupedLogs<'a> {
GroupedLogs {
) -> LogsByIdentifier<'a> {
LogsByIdentifier {
lines,
app,
filter,
grouping,
}
}
impl StatefulWidget for GroupedLogs<'_> {
impl StatefulWidget for LogsByIdentifier<'_> {
type State = ScrollbarTableState;
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State)
@ -45,7 +42,7 @@ impl StatefulWidget for GroupedLogs<'_> {
.copied()
.filter(|line| line.matches(self.filter))
.nth(state.selected())
.unwrap_or(self.app.lines.first());
.unwrap_or(self.lines.first().unwrap());
let par = match self.grouping {
GroupedLogGrouping::Message => Paragraph::new(format!(

View file

@ -5,7 +5,7 @@ use ratatui::layout::Constraint;
use ratatui::text::Text;
use ratatui::widgets::{Cell, Row};
pub fn error_list<'a>(app: &'a App<'a>) -> ScrollbarTable<'a> {
pub fn error_list<'a>(app: &App<'a>) -> ScrollbarTable<'a> {
let header = [Text::from("Error"), Text::from("Line")]
.into_iter()
.map(Cell::from)

View file

@ -11,7 +11,7 @@ pub enum FooterParams<'a> {
FilterInput { page: UiPage, filter: &'a Filter },
}
pub fn footer<'a>(app: &App<'a>, params: FooterParams<'a>) -> Table<'a> {
pub fn footer<'a>(app: &App, params: FooterParams<'a>) -> Table<'a> {
let footer_style = Style::default()
.bg(tailwind::BLACK)
.fg(tailwind::GREEN.c600);

View file

@ -1,21 +1,19 @@
use crate::app::Filter;
use crate::grouping::{GroupedLine, GroupingResult, LogGrouping};
use crate::grouping::{Grouping, GroupingResult, LogGrouping};
use crate::ui::style::TABLE_HEADER_STYLE;
use crate::ui::table::ScrollbarTable;
use ratatui::prelude::*;
use ratatui::widgets::{Cell, Row};
use std::borrow::Cow;
use std::iter::once;
use std::ops::RangeInclusive;
use time::OffsetDateTime;
pub fn grouping_list<'a, G: GroupingResult>(
all: &'a LogGrouping<'a, G>,
items: &'a [LogGrouping<'a, G>],
time_range: RangeInclusive<OffsetDateTime>,
filter: &Filter,
) -> ScrollbarTable<'a> {
let header = G::Lines::HEADER
let header = G::Grouping::HEADER
.iter()
.copied()
.chain([("Time", Alignment::Left), ("Count", Alignment::Left)]);
@ -28,10 +26,14 @@ pub fn grouping_list<'a, G: GroupingResult>(
.height(1);
ScrollbarTable::new(
once(all)
.chain(items.iter().filter(|result| result.matches(filter)))
items
.iter()
.filter(|result| result.matches(filter))
.map(|result| grouped_row(result, time_range.clone())),
G::Lines::WIDTHS,
G::Grouping::WIDTHS
.iter()
.copied()
.chain([Constraint::Length(10), Constraint::Min(10)]),
)
.header(header)
}
@ -46,7 +48,7 @@ fn grouped_row<'a, G: GroupingResult>(
Cow::from(grouping.sparkline(time_range)),
Cow::from(grouping.count().to_string()),
]);
Row::new(columns).height(match_result.len() as u16)
Row::new(columns).height(match_result.height() as u16)
} else {
Row::new([
Text::from(grouping.name.unwrap_or_default()),

View file

@ -1,3 +1,4 @@
use crate::app::App;
use crate::ui::find_hit_row;
use crate::ui::state::{Mode, UiPage, UiState};
use ratatui::crossterm::event;
@ -29,7 +30,7 @@ pub enum PopMode {
Word,
}
pub fn handle_events(page: UiPage, ui_state: &UiState) -> io::Result<Option<UiEvent>> {
pub fn handle_events(page: UiPage, ui_state: &UiState, app: &App) -> io::Result<Option<UiEvent>> {
if event::poll(Duration::from_millis(50))? {
match event::read()? {
Event::Key(key) if key.kind == event::KeyEventKind::Press => {
@ -76,7 +77,7 @@ pub fn handle_events(page: UiPage, ui_state: &UiState) -> io::Result<Option<UiEv
MouseEventKind::ScrollUp => Some(UiEvent::Scroll(-1)),
MouseEventKind::ScrollDown => Some(UiEvent::Scroll(1)),
MouseEventKind::Down(MouseButton::Left) => {
find_hit_row(mouse.row, ui_state).map(UiEvent::Enter)
find_hit_row(mouse.row, ui_state, app).map(UiEvent::Enter)
}
_ => None,
})

View file

@ -1,16 +1,17 @@
use crate::app::App;
use crate::error::UiError;
use crate::matcher::MatchResult;
use crate::ui::by_identifier::logs_by_identifier;
use crate::ui::error_list::error_list;
use crate::ui::footer::footer;
use crate::ui::grouped_logs::grouped_logs;
use crate::ui::grouping_list::grouping_list;
use crate::ui::histogram::UiHistogram;
use crate::ui::input::handle_events;
use crate::ui::single_group::single_group;
use crate::ui::single_log::single_log;
use crate::ui::single_match::grouped_lines;
use crate::ui::state::{
ErrorLinesState, ErrorState, GroupedLogsState, LogState, MatchListState, MatchState, UiState,
ErrorLinesState, ErrorState, GroupListState, GroupState, LogState, LogsByIdentifierState,
UiState,
};
use ratatui::crossterm::event::{DisableMouseCapture, EnableMouseCapture};
use ratatui::crossterm::terminal::{
@ -25,24 +26,24 @@ use std::io;
use std::io::stdout;
use std::panic::{set_hook, take_hook};
mod by_identifier;
mod error_list;
mod footer;
mod grouped_logs;
mod grouping_list;
mod histogram;
mod input;
mod single_group;
mod single_log;
mod single_match;
mod state;
pub mod style;
mod table;
pub fn run_ui(app: App) -> Result<(), UiError> {
pub fn run_ui<'a>(app: App<'a>) -> Result<(), UiError> {
init_panic_hook();
let mut terminal = init_tui()?;
terminal.clear().ok();
let mut ui_state = UiState::new(&app);
let mut ui_state: UiState = UiState::new(&app);
let mut update = true;
while !matches!(ui_state, UiState::Quit) {
@ -50,7 +51,7 @@ pub fn run_ui(app: App) -> Result<(), UiError> {
terminal.draw(|frame| ui(frame, &app, &mut ui_state))?;
}
update = false;
if let Some(event) = handle_events(ui_state.page(), &ui_state)? {
if let Some(event) = handle_events(ui_state.page(), &ui_state, &app)? {
(update, ui_state) = ui_state.process(event, &app);
}
}
@ -83,9 +84,9 @@ pub fn restore_tui() -> io::Result<()> {
Ok(())
}
fn find_hit_row(row: u16, ui_state: &UiState) -> Option<usize> {
fn find_hit_row(row: u16, ui_state: &UiState, app: &App) -> Option<usize> {
if let Some(table_row) = row.checked_sub(ui_state.content_offset()) {
let selected = ui_state.index_for_row(table_row as usize);
let selected = ui_state.index_for_row(table_row as usize, app);
if selected < ui_state.row_count() {
Some(selected)
} else {
@ -110,28 +111,23 @@ fn ui(frame: &mut Frame, app: &App, state: &mut UiState) {
match state {
UiState::Quit => {}
UiState::MatchList(MatchListState {
UiState::GroupList(GroupListState {
table_state,
filter,
..
}) => {
let selected = table_state.selected();
let histogram = if selected == 0 {
app.all.histogram(app.time_range())
} else {
let log_match = &app.matches[selected - 1];
log_match.histogram(app.time_range())
};
let histogram = app.matches[selected].histogram(app.time_range());
frame.render_widget(UiHistogram::new(histogram), layout[0]);
frame.render_stateful_widget(
grouping_list::<MatchResult>(&app.all, &app.matches, app.time_range(), filter),
grouping_list::<MatchResult>(app.matches, app.time_range(), filter),
layout[1],
table_state,
);
frame.render_widget(footer(app, state.footer_params()), layout[2]);
}
UiState::Match(MatchState {
UiState::Group(GroupState {
result,
table_state,
filter,
@ -139,9 +135,9 @@ fn ui(frame: &mut Frame, app: &App, state: &mut UiState) {
}) => {
let selected = table_state.selected();
let selected_group = if selected == 0 {
&result.all
&result.lines
} else {
&result.grouped[selected - 1]
&result.by_identifier()[selected - 1]
};
frame.render_widget(
@ -149,13 +145,18 @@ fn ui(frame: &mut Frame, app: &App, state: &mut UiState) {
layout[0],
);
frame.render_stateful_widget(
grouped_lines(app, result, filter),
single_group(
app.time_range(),
&result.lines,
result.by_identifier(),
filter,
),
layout[1],
table_state,
);
frame.render_widget(footer(app, state.footer_params()), layout[2]);
}
UiState::GroupedLogs(GroupedLogsState {
UiState::ByIdentifier(LogsByIdentifierState {
lines,
table_state,
filter,
@ -163,7 +164,7 @@ fn ui(frame: &mut Frame, app: &App, state: &mut UiState) {
..
}) => {
frame.render_stateful_widget(
grouped_logs(app, lines, filter, *grouping),
logs_by_identifier(lines, filter, *grouping),
layout[0].union(layout[1]),
table_state,
);

View file

@ -1,6 +1,4 @@
use crate::app::{App, Filter, LineSet};
use crate::grouping::LogGrouping;
use crate::matcher::MatchResult;
use crate::app::{Filter, LineSet};
use crate::ui::style::TABLE_HEADER_STYLE;
use crate::ui::table::{ScrollbarTable, ScrollbarTableState};
use ratatui::buffer::Buffer;
@ -12,32 +10,35 @@ use std::iter::once;
use std::ops::RangeInclusive;
use time::OffsetDateTime;
pub fn grouped_lines<'a>(
app: &'a App<'a>,
log_match: &'a LogGrouping<'a, MatchResult>,
pub fn single_group<'a>(
time_range: RangeInclusive<OffsetDateTime>,
all: &'a LineSet<'a>,
unique: &'a [LineSet<'a>],
filter: &'a Filter,
) -> SingleMatchTable<'a> {
SingleMatchTable {
app,
log_match,
) -> SingleGroup<'a> {
SingleGroup {
time_range,
all,
unique,
filter,
}
}
pub struct SingleMatchTable<'a> {
app: &'a App<'a>,
log_match: &'a LogGrouping<'a, MatchResult>,
pub struct SingleGroup<'a> {
time_range: RangeInclusive<OffsetDateTime>,
all: &'a LineSet<'a>,
unique: &'a [LineSet<'a>],
filter: &'a Filter,
}
impl StatefulWidget for SingleMatchTable<'_> {
impl StatefulWidget for SingleGroup<'_> {
type State = ScrollbarTableState;
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State)
where
Self: Sized,
{
let grouped = &self.log_match.grouped;
let grouped = self.unique;
let header = [
Text::from("Level"),
Text::from("App"),
@ -63,8 +64,8 @@ impl StatefulWidget for SingleMatchTable<'_> {
Text::from("All lines"),
Text::from(""),
Text::from(""),
Text::from(self.log_match.sparkline(self.app.time_range())),
Text::from(self.log_match.count().to_string()),
Text::from(self.all.sparkline(self.time_range.clone())),
Text::from(self.all.len().to_string()),
]))
.chain(
grouped
@ -73,7 +74,7 @@ impl StatefulWidget for SingleMatchTable<'_> {
.enumerate()
.map(|(i, group)| {
group_row(
self.app.time_range(),
self.time_range.clone(),
group,
i.abs_diff(state.selected()) < 100,
)

View file

@ -16,9 +16,9 @@ use std::sync::Arc;
#[derive(Clone, From, PartialEq)]
pub enum UiState<'a> {
MatchList(MatchListState<'a>),
Match(MatchState<'a>),
GroupedLogs(GroupedLogsState<'a>),
GroupList(GroupListState),
Group(GroupState<'a>),
ByIdentifier(LogsByIdentifierState<'a>),
Log(LogState<'a>),
Errors(ErrorLinesState<'a>),
Error(ErrorState<'a>),
@ -32,22 +32,19 @@ pub enum Mode {
}
#[derive(Clone)]
pub struct MatchListState<'a> {
app: &'a App<'a>,
pub struct GroupListState {
pub table_state: ScrollbarTableState,
pub filter: Filter,
mode: Mode,
}
impl<'a> MatchListState<'a> {
impl GroupListState {
fn selected(&self) -> usize {
self.table_state.selected()
}
fn enter(self, selected: usize, app: &'a App) -> UiState<'a> {
let result = if selected == 0 {
&app.all
} else if self.filter.is_empty() {
fn enter<'a>(self, selected: usize, app: &App<'a>) -> UiState<'a> {
let result = if self.filter.is_empty() {
&app.matches[selected - 1]
} else {
app.matches
@ -57,8 +54,8 @@ impl<'a> MatchListState<'a> {
.unwrap_or(app.matches.last().unwrap())
};
let table_state = ScrollbarTableState::new(result.grouped.len() + 1);
UiState::Match(MatchState {
let table_state = ScrollbarTableState::new(result.by_identifier().len() + 1);
UiState::Group(GroupState {
result,
table_state,
previous: Box::new(self.into()),
@ -68,14 +65,14 @@ impl<'a> MatchListState<'a> {
}
}
impl PartialEq for MatchListState<'_> {
impl PartialEq for GroupListState {
fn eq(&self, _other: &Self) -> bool {
true
}
}
#[derive(Clone)]
pub struct MatchState<'a> {
pub struct GroupState<'a> {
pub result: &'a LogGrouping<'a, MatchResult>,
pub table_state: ScrollbarTableState,
pub previous: Box<UiState<'a>>,
@ -83,7 +80,7 @@ pub struct MatchState<'a> {
mode: Mode,
}
impl<'a> MatchState<'a> {
impl<'a> GroupState<'a> {
fn selected(&self) -> usize {
self.table_state.selected()
}
@ -93,12 +90,12 @@ impl<'a> MatchState<'a> {
table_state.select(Some(0));
let selected_line = if selected == 0 {
&self.result.all
&self.result.lines
} else if self.filter.is_empty() {
&self.result.grouped[selected - 1]
&self.result.by_identifier()[selected - 1]
} else {
self.result
.grouped
.by_identifier()
.iter()
.filter(|grouped| grouped.matches(&self.filter))
.nth(selected - 1)
@ -106,7 +103,7 @@ impl<'a> MatchState<'a> {
};
let lines = selected_line.lines.as_slice();
let table_state = ScrollbarTableState::new(lines.len());
UiState::GroupedLogs(GroupedLogsState {
UiState::ByIdentifier(LogsByIdentifierState {
lines: lines.into(),
table_state,
previous: Box::new(self.into()),
@ -117,7 +114,7 @@ impl<'a> MatchState<'a> {
}
}
impl PartialEq for MatchState<'_> {
impl PartialEq for GroupState<'_> {
fn eq(&self, other: &Self) -> bool {
self.result.result == other.result.result
}
@ -130,7 +127,7 @@ pub enum GroupedLogGrouping {
}
#[derive(Clone)]
pub struct GroupedLogsState<'a> {
pub struct LogsByIdentifierState<'a> {
pub lines: Cow<'a, [&'a LogLine<'a>]>,
pub table_state: ScrollbarTableState,
pub previous: Box<UiState<'a>>,
@ -139,7 +136,7 @@ pub struct GroupedLogsState<'a> {
pub grouping: GroupedLogGrouping,
}
impl<'a> GroupedLogsState<'a> {
impl<'a> LogsByIdentifierState<'a> {
fn selected(&self) -> usize {
self.table_state.selected()
}
@ -157,7 +154,7 @@ impl<'a> GroupedLogsState<'a> {
}
}
fn enter(self, selected: usize, app: &'a App<'a>) -> UiState<'a> {
fn enter(self, selected: usize, app: &App<'a>) -> UiState<'a> {
let log = self.get_selected(selected);
let raw_line = app.get_source_line(log.line_number).unwrap();
let full_line = match parse_line_full(raw_line) {
@ -187,12 +184,12 @@ impl<'a> GroupedLogsState<'a> {
})
}
fn by_request(self, selected: usize, app: &'a App<'a>) -> UiState<'a> {
fn by_request(self, selected: usize, app: &App<'a>) -> UiState<'a> {
let log = self.get_selected(selected);
let lines: Vec<_> = app.lines_by_request(&log.request_id).collect();
let table_state = ScrollbarTableState::new(lines.len());
UiState::GroupedLogs(GroupedLogsState {
UiState::ByIdentifier(LogsByIdentifierState {
lines: lines.into(),
mode: Mode::Normal,
filter: Filter::default(),
@ -203,7 +200,7 @@ impl<'a> GroupedLogsState<'a> {
}
}
impl PartialEq for GroupedLogsState<'_> {
impl PartialEq for LogsByIdentifierState<'_> {
fn eq(&self, other: &Self) -> bool {
self.lines == other.lines
}
@ -230,11 +227,11 @@ pub struct LogState<'a> {
}
impl<'a> LogState<'a> {
fn by_request(self, app: &'a App<'a>) -> UiState<'a> {
fn by_request(self, app: &App<'a>) -> UiState<'a> {
let lines: Vec<_> = app.lines_by_request(&self.log.request_id).collect();
let table_state = ScrollbarTableState::new(lines.len());
UiState::GroupedLogs(GroupedLogsState {
UiState::ByIdentifier(LogsByIdentifierState {
lines: lines.into(),
mode: Mode::Normal,
filter: Filter::default(),
@ -252,11 +249,10 @@ impl PartialEq for LogState<'_> {
}
impl<'a> UiState<'a> {
pub fn new(app: &'a App<'a>) -> Self {
pub fn new(app: &App) -> Self {
let mut table_state = TableState::default();
table_state.select(Some(0));
UiState::MatchList(MatchListState {
app,
UiState::GroupList(GroupListState {
table_state: ScrollbarTableState::new(app.match_lines()),
filter: Filter::default(),
mode: Mode::Normal,
@ -265,9 +261,9 @@ impl<'a> UiState<'a> {
pub fn page(&self) -> UiPage {
match self {
UiState::Quit | UiState::MatchList(_) => UiPage::MatchList,
UiState::Match(_) => UiPage::Match,
UiState::GroupedLogs(_) => UiPage::Logs,
UiState::Quit | UiState::GroupList(_) => UiPage::MatchList,
UiState::Group(_) => UiPage::Match,
UiState::ByIdentifier(_) => UiPage::Logs,
UiState::Log(_) => UiPage::Log,
UiState::Errors(_) => UiPage::Errors,
UiState::Error(_) => UiPage::Error,
@ -276,45 +272,45 @@ impl<'a> UiState<'a> {
pub fn mode(&self) -> Mode {
match self {
UiState::MatchList(state) => state.mode,
UiState::Match(state) => state.mode,
UiState::GroupedLogs(state) => state.mode,
UiState::GroupList(state) => state.mode,
UiState::Group(state) => state.mode,
UiState::ByIdentifier(state) => state.mode,
_ => Mode::Normal,
}
}
pub fn set_mode(&mut self, mode: Mode) {
match self {
UiState::MatchList(state) => state.mode = mode,
UiState::Match(state) => state.mode = mode,
UiState::GroupedLogs(state) => state.mode = mode,
UiState::GroupList(state) => state.mode = mode,
UiState::Group(state) => state.mode = mode,
UiState::ByIdentifier(state) => state.mode = mode,
_ => {}
}
}
pub fn filter(&self) -> Option<&Filter> {
match self {
UiState::MatchList(state) => Some(&state.filter),
UiState::Match(state) => Some(&state.filter),
UiState::GroupedLogs(state) => Some(&state.filter),
UiState::GroupList(state) => Some(&state.filter),
UiState::Group(state) => Some(&state.filter),
UiState::ByIdentifier(state) => Some(&state.filter),
_ => None,
}
}
pub fn filter_mut(&mut self) -> Option<&mut Filter> {
match self {
UiState::MatchList(state) => Some(&mut state.filter),
UiState::Match(state) => Some(&mut state.filter),
UiState::GroupedLogs(state) => Some(&mut state.filter),
UiState::GroupList(state) => Some(&mut state.filter),
UiState::Group(state) => Some(&mut state.filter),
UiState::ByIdentifier(state) => Some(&mut state.filter),
_ => None,
}
}
fn table_state(&self) -> Option<&ScrollbarTableState> {
match self {
UiState::MatchList(state) => Some(&state.table_state),
UiState::Match(state) => Some(&state.table_state),
UiState::GroupedLogs(state) => Some(&state.table_state),
UiState::GroupList(state) => Some(&state.table_state),
UiState::Group(state) => Some(&state.table_state),
UiState::ByIdentifier(state) => Some(&state.table_state),
UiState::Log(state) => Some(&state.table_state),
UiState::Errors(state) => Some(&state.table_state),
_ => None,
@ -323,9 +319,9 @@ impl<'a> UiState<'a> {
fn table_state_mut(&mut self) -> Option<&mut ScrollbarTableState> {
match self {
UiState::MatchList(state) => Some(&mut state.table_state),
UiState::Match(state) => Some(&mut state.table_state),
UiState::GroupedLogs(state) => Some(&mut state.table_state),
UiState::GroupList(state) => Some(&mut state.table_state),
UiState::Group(state) => Some(&mut state.table_state),
UiState::ByIdentifier(state) => Some(&mut state.table_state),
UiState::Log(state) => Some(&mut state.table_state),
UiState::Errors(state) => Some(&mut state.table_state),
_ => None,
@ -348,9 +344,9 @@ impl<'a> UiState<'a> {
}
}
pub fn index_for_row(&self, row: usize) -> usize {
pub fn index_for_row(&self, row: usize, app: &App) -> usize {
match self {
UiState::MatchList(MatchListState { app, filter, .. }) => {
UiState::GroupList(GroupListState { filter, .. }) => {
let mut total_height = 0;
let match_row_counts = app
.matches
@ -381,9 +377,9 @@ impl<'a> UiState<'a> {
/// get the offset of the "main content" from the top of the screen
pub fn content_offset(&self) -> u16 {
match self {
UiState::MatchList(_) => UI_HEADER_SIZE + 1,
UiState::Match(_) => UI_HEADER_SIZE + 1,
UiState::GroupedLogs(_) => UI_HEADER_SIZE + 1,
UiState::GroupList(_) => UI_HEADER_SIZE + 1,
UiState::Group(_) => UI_HEADER_SIZE + 1,
UiState::ByIdentifier(_) => UI_HEADER_SIZE + 1,
UiState::Log(_) => 0,
UiState::Errors(_) => 0,
UiState::Error(_) => 0,
@ -391,12 +387,12 @@ impl<'a> UiState<'a> {
}
}
pub fn process(self, event: UiEvent, app: &'a App<'a>) -> (bool, UiState<'a>) {
pub fn process(self, event: UiEvent, app: &App<'a>) -> (bool, UiState<'a>) {
match (self, event) {
(UiState::Quit, _) => (true, UiState::Quit),
(_, UiEvent::Quit) => (true, UiState::Quit),
(
UiState::MatchList(MatchListState {
UiState::GroupList(GroupListState {
mode: Mode::Normal, ..
}),
UiEvent::Back,
@ -425,14 +421,14 @@ impl<'a> UiState<'a> {
}
(true, state)
}
(UiState::MatchList(state), UiEvent::Select) => {
(UiState::GroupList(state), UiEvent::Select) => {
let selected = state.selected();
(true, state.enter(selected, app))
}
(UiState::MatchList(state), UiEvent::Enter(selected)) => {
(UiState::GroupList(state), UiEvent::Enter(selected)) => {
(true, state.enter(selected, app))
}
(UiState::MatchList(state), UiEvent::Errors) => {
(UiState::GroupList(state), UiEvent::Errors) => {
let table_state = ScrollbarTableState::new(app.error_count());
(
true,
@ -442,19 +438,19 @@ impl<'a> UiState<'a> {
}),
)
}
(UiState::Match(state), UiEvent::Select) => {
(UiState::Group(state), UiEvent::Select) => {
let selected = state.selected();
(true, state.enter(selected))
}
(UiState::Match(state), UiEvent::Enter(selected)) => (true, state.enter(selected)),
(UiState::GroupedLogs(state), UiEvent::Select) => {
(UiState::Group(state), UiEvent::Enter(selected)) => (true, state.enter(selected)),
(UiState::ByIdentifier(state), UiEvent::Select) => {
let selected = state.selected();
(true, state.enter(selected, app))
}
(UiState::GroupedLogs(state), UiEvent::Enter(selected)) => {
(UiState::ByIdentifier(state), UiEvent::Enter(selected)) => {
(true, state.enter(selected, app))
}
(UiState::GroupedLogs(state), UiEvent::Copy) => {
(UiState::ByIdentifier(state), UiEvent::Copy) => {
let selected = state.selected();
let mut table_state = TableState::default();
table_state.select(Some(0));
@ -462,7 +458,7 @@ impl<'a> UiState<'a> {
let line = state.lines[selected];
let raw = app.get_source_line(line.line_number).unwrap_or_default();
copy_osc(raw);
(false, UiState::GroupedLogs(state))
(false, UiState::ByIdentifier(state))
}
(UiState::Log(state), UiEvent::Copy) => {
let raw = app
@ -471,7 +467,7 @@ impl<'a> UiState<'a> {
copy_osc(raw);
(false, UiState::Log(state))
}
(UiState::GroupedLogs(state), UiEvent::ByRequest) => {
(UiState::ByIdentifier(state), UiEvent::ByRequest) => {
let selected = state.selected();
(true, state.by_request(selected, app))
}
@ -512,7 +508,7 @@ impl<'a> UiState<'a> {
(true, ui)
}
(
mut ui @ UiState::MatchList(MatchListState {
mut ui @ UiState::GroupList(GroupListState {
mode: Mode::FilterInput,
..
}),
@ -526,8 +522,8 @@ impl<'a> UiState<'a> {
}
(
UiState::Match(MatchState { previous, .. })
| UiState::GroupedLogs(GroupedLogsState { previous, .. })
UiState::Group(GroupState { previous, .. })
| UiState::ByIdentifier(LogsByIdentifierState { previous, .. })
| UiState::Log(LogState { previous, .. })
| UiState::Errors(ErrorLinesState { previous, .. }),
UiEvent::Back,