rusticity_term/session/
ui.rs

1use super::Session;
2use crate::common::SortDirection;
3
4pub fn render_session_picker(
5    frame: &mut ratatui::Frame,
6    app: &crate::app::App,
7    area: ratatui::prelude::Rect,
8    centered_rect: fn(u16, u16, ratatui::prelude::Rect) -> ratatui::prelude::Rect,
9) {
10    use crate::ui::table::{render_table, Column as TableColumn, TableConfig};
11    use ratatui::{prelude::*, widgets::*};
12
13    let popup_area = centered_rect(80, 70, area);
14
15    let chunks = Layout::default()
16        .direction(Direction::Vertical)
17        .constraints([Constraint::Length(3), Constraint::Min(0)])
18        .split(popup_area);
19
20    let cursor = "█";
21    let filter = Paragraph::new(Line::from(vec![
22        Span::raw(&app.session_filter),
23        Span::styled(cursor, Style::default().fg(Color::Green)),
24    ]))
25    .block(
26        Block::default()
27            .title(" 🔍 ")
28            .borders(Borders::ALL)
29            .border_style(crate::ui::active_border()),
30    )
31    .style(Style::default());
32
33    frame.render_widget(Clear, popup_area);
34    frame.render_widget(filter, chunks[0]);
35
36    struct SessionTimestampColumn;
37    impl TableColumn<Session> for SessionTimestampColumn {
38        fn name(&self) -> &str {
39            "Timestamp"
40        }
41        fn width(&self) -> u16 {
42            25
43        }
44        fn render(&self, item: &Session) -> (String, Style) {
45            (item.timestamp.clone(), Style::default())
46        }
47    }
48
49    struct SessionProfileColumn;
50    impl TableColumn<Session> for SessionProfileColumn {
51        fn name(&self) -> &str {
52            "Profile"
53        }
54        fn width(&self) -> u16 {
55            25
56        }
57        fn render(&self, item: &Session) -> (String, Style) {
58            (item.profile.clone(), Style::default())
59        }
60    }
61
62    struct SessionRegionColumn;
63    impl TableColumn<Session> for SessionRegionColumn {
64        fn name(&self) -> &str {
65            "Region"
66        }
67        fn width(&self) -> u16 {
68            15
69        }
70        fn render(&self, item: &Session) -> (String, Style) {
71            (item.region.clone(), Style::default())
72        }
73    }
74
75    struct SessionAccountColumn;
76    impl TableColumn<Session> for SessionAccountColumn {
77        fn name(&self) -> &str {
78            "Account"
79        }
80        fn width(&self) -> u16 {
81            15
82        }
83        fn render(&self, item: &Session) -> (String, Style) {
84            (item.account_id.clone(), Style::default())
85        }
86    }
87
88    struct SessionTabsColumn;
89    impl TableColumn<Session> for SessionTabsColumn {
90        fn name(&self) -> &str {
91            "Tabs"
92        }
93        fn width(&self) -> u16 {
94            8
95        }
96        fn render(&self, item: &Session) -> (String, Style) {
97            (item.tabs.len().to_string(), Style::default())
98        }
99    }
100
101    let columns: Vec<Box<dyn TableColumn<Session>>> = vec![
102        Box::new(SessionTimestampColumn),
103        Box::new(SessionProfileColumn),
104        Box::new(SessionRegionColumn),
105        Box::new(SessionAccountColumn),
106        Box::new(SessionTabsColumn),
107    ];
108
109    let filtered = app.get_filtered_sessions();
110    let config = TableConfig {
111        items: filtered,
112        selected_index: app.session_picker_selected,
113        expanded_index: None,
114        columns: &columns,
115        sort_column: "Timestamp",
116        sort_direction: SortDirection::Desc,
117        title: " Sessions ".to_string(),
118        area: chunks[1],
119        get_expanded_content: None,
120        is_active: true,
121    };
122
123    render_table(frame, config);
124}