Skip to main content

TableBuilder

Struct TableBuilder 

Source
pub struct TableBuilder { /* private fields */ }
Expand description

Builder for Table views.

Implementations§

Source§

impl TableBuilder

Source

pub fn new() -> Self

Source

pub fn column(self, header: impl Into<String>) -> Self

Add a column with just a header (auto width, left aligned, not sortable).

Examples found in repository?
examples/17_table.rs (line 166)
21    fn render(&self, cx: Scope) -> View {
22        let show_help = state!(cx, || false);
23
24        // F1 toggles help
25        cx.use_command(
26            KeyBinding::key(KeyCode::F(1)),
27            with!(show_help => move || show_help.update(|v| *v = !*v)),
28        );
29
30        // Track selected row
31        let selected = state!(cx, || 0usize);
32
33        // Track sort state (column index, ascending)
34        let sort_state = state!(cx, || None::<(usize, bool)>);
35
36        // Sample pod data (like k9s)
37        let base_data = vec![
38            vec![
39                "nginx-pod".to_string(),
40                "Running".to_string(),
41                "12%".to_string(),
42                "256Mi".to_string(),
43                "2h".to_string(),
44            ],
45            vec![
46                "redis-cache".to_string(),
47                "Running".to_string(),
48                "8%".to_string(),
49                "128Mi".to_string(),
50                "5d".to_string(),
51            ],
52            vec![
53                "api-server".to_string(),
54                "Running".to_string(),
55                "45%".to_string(),
56                "512Mi".to_string(),
57                "1h".to_string(),
58            ],
59            vec![
60                "db-postgres".to_string(),
61                "Running".to_string(),
62                "23%".to_string(),
63                "1Gi".to_string(),
64                "3d".to_string(),
65            ],
66            vec![
67                "worker-1".to_string(),
68                "Pending".to_string(),
69                "0%".to_string(),
70                "0Mi".to_string(),
71                "5m".to_string(),
72            ],
73            vec![
74                "worker-2".to_string(),
75                "Running".to_string(),
76                "67%".to_string(),
77                "384Mi".to_string(),
78                "45m".to_string(),
79            ],
80            vec![
81                "frontend".to_string(),
82                "Running".to_string(),
83                "5%".to_string(),
84                "64Mi".to_string(),
85                "12h".to_string(),
86            ],
87            vec![
88                "metrics".to_string(),
89                "CrashLoop".to_string(),
90                "0%".to_string(),
91                "32Mi".to_string(),
92                "2m".to_string(),
93            ],
94        ];
95
96        // Sort data based on current sort state
97        let mut rows = base_data.clone();
98        if let Some((col, ascending)) = sort_state.get() {
99            rows.sort_by(|a, b| {
100                let a_val = a.get(col).map(|s| s.as_str()).unwrap_or("");
101                let b_val = b.get(col).map(|s| s.as_str()).unwrap_or("");
102                if ascending {
103                    a_val.cmp(b_val)
104                } else {
105                    b_val.cmp(a_val)
106                }
107            });
108        }
109
110        let on_select = with!(selected => move |idx: usize| {
111            selected.set(idx);
112        });
113
114        let on_sort = with!(sort_state => move |col: usize, asc: bool| {
115            sort_state.set(Some((col, asc)));
116        });
117
118        let on_activate = with!(selected => move |idx: usize| {
119            // In a real app, this might open a details view
120            selected.set(idx);
121        });
122
123        let selected_name = rows
124            .get(selected.get())
125            .and_then(|r| r.first())
126            .map(|s| s.as_str())
127            .unwrap_or("None");
128
129        let sort_info = match sort_state.get() {
130            Some((col, asc)) => {
131                let col_name = match col {
132                    0 => "NAME",
133                    1 => "STATUS",
134                    2 => "CPU",
135                    3 => "MEMORY",
136                    4 => "AGE",
137                    _ => "?",
138                };
139                format!(
140                    "Sorted by {} ({})",
141                    col_name,
142                    if asc { "asc" } else { "desc" }
143                )
144            }
145            None => "Unsorted".to_string(),
146        };
147
148        View::vstack()
149            .child(
150                View::styled_text("Pod Dashboard")
151                    .color(Color::Cyan)
152                    .bold()
153                    .build(),
154            )
155            .child(
156                View::styled_text(format!("Selected: {} | {}", selected_name, sort_info))
157                    .dim()
158                    .build(),
159            )
160            .child(
161                View::boxed()
162                    .flex(1)
163                    .border(true)
164                    .child(
165                        View::table()
166                            .column("NAME")
167                            .column_with(TableColumn::new("STATUS").width(ColumnWidth::Fixed(12)))
168                            .column_with(
169                                TableColumn::new("CPU")
170                                    .width(ColumnWidth::Fixed(8))
171                                    .align(TextAlign::Right),
172                            )
173                            .column_with(
174                                TableColumn::new("MEMORY")
175                                    .width(ColumnWidth::Fixed(10))
176                                    .align(TextAlign::Right),
177                            )
178                            .column_with(
179                                TableColumn::new("AGE")
180                                    .width(ColumnWidth::Fixed(8))
181                                    .align(TextAlign::Right),
182                            )
183                            .rows(rows)
184                            .selected(selected.get())
185                            .sort(sort_state.get())
186                            .on_select(on_select)
187                            .on_sort(on_sort)
188                            .on_activate(on_activate)
189                            .build(),
190                    )
191                    .build(),
192            )
193            .child(
194                View::styled_text("↑↓/jk: navigate | Enter: activate | F1 help | Ctrl+Q: quit")
195                    .dim()
196                    .build(),
197            )
198            .child(
199                View::modal()
200                    .visible(show_help.get())
201                    .title("Example 17: Table")
202                    .on_dismiss(with!(show_help => move || show_help.set(false)))
203                    .child(
204                        View::vstack()
205                            .child(View::styled_text("What you're seeing").bold().build())
206                            .child(View::text("• Data table with sortable columns"))
207                            .child(View::text("• Row selection and activation"))
208                            .child(View::text("• Fixed and flexible column widths"))
209                            .child(View::gap(1))
210                            .child(View::styled_text("Key concepts").bold().build())
211                            .child(View::text("• View::table() for tabular data"))
212                            .child(View::text("• TableColumn for column config"))
213                            .child(View::text("• ColumnWidth::Fixed or ColumnWidth::Flex"))
214                            .child(View::text("• on_sort callback for sorting"))
215                            .child(View::gap(1))
216                            .child(View::styled_text("Try this").bold().build())
217                            .child(View::text("• Navigate rows with arrow keys"))
218                            .child(View::text("• Press Enter to activate a row"))
219                            .child(View::text("• Sorting is managed via on_sort"))
220                            .child(View::gap(1))
221                            .child(View::styled_text("Next up").bold().build())
222                            .child(View::text("→ 18_progress_bar: progress indicators"))
223                            .child(View::gap(1))
224                            .child(View::styled_text("Press Escape to close").dim().build())
225                            .build(),
226                    )
227                    .build(),
228            )
229            .build()
230    }
Source

pub fn column_with(self, column: TableColumn) -> Self

Add a column with full configuration.

Examples found in repository?
examples/17_table.rs (line 167)
21    fn render(&self, cx: Scope) -> View {
22        let show_help = state!(cx, || false);
23
24        // F1 toggles help
25        cx.use_command(
26            KeyBinding::key(KeyCode::F(1)),
27            with!(show_help => move || show_help.update(|v| *v = !*v)),
28        );
29
30        // Track selected row
31        let selected = state!(cx, || 0usize);
32
33        // Track sort state (column index, ascending)
34        let sort_state = state!(cx, || None::<(usize, bool)>);
35
36        // Sample pod data (like k9s)
37        let base_data = vec![
38            vec![
39                "nginx-pod".to_string(),
40                "Running".to_string(),
41                "12%".to_string(),
42                "256Mi".to_string(),
43                "2h".to_string(),
44            ],
45            vec![
46                "redis-cache".to_string(),
47                "Running".to_string(),
48                "8%".to_string(),
49                "128Mi".to_string(),
50                "5d".to_string(),
51            ],
52            vec![
53                "api-server".to_string(),
54                "Running".to_string(),
55                "45%".to_string(),
56                "512Mi".to_string(),
57                "1h".to_string(),
58            ],
59            vec![
60                "db-postgres".to_string(),
61                "Running".to_string(),
62                "23%".to_string(),
63                "1Gi".to_string(),
64                "3d".to_string(),
65            ],
66            vec![
67                "worker-1".to_string(),
68                "Pending".to_string(),
69                "0%".to_string(),
70                "0Mi".to_string(),
71                "5m".to_string(),
72            ],
73            vec![
74                "worker-2".to_string(),
75                "Running".to_string(),
76                "67%".to_string(),
77                "384Mi".to_string(),
78                "45m".to_string(),
79            ],
80            vec![
81                "frontend".to_string(),
82                "Running".to_string(),
83                "5%".to_string(),
84                "64Mi".to_string(),
85                "12h".to_string(),
86            ],
87            vec![
88                "metrics".to_string(),
89                "CrashLoop".to_string(),
90                "0%".to_string(),
91                "32Mi".to_string(),
92                "2m".to_string(),
93            ],
94        ];
95
96        // Sort data based on current sort state
97        let mut rows = base_data.clone();
98        if let Some((col, ascending)) = sort_state.get() {
99            rows.sort_by(|a, b| {
100                let a_val = a.get(col).map(|s| s.as_str()).unwrap_or("");
101                let b_val = b.get(col).map(|s| s.as_str()).unwrap_or("");
102                if ascending {
103                    a_val.cmp(b_val)
104                } else {
105                    b_val.cmp(a_val)
106                }
107            });
108        }
109
110        let on_select = with!(selected => move |idx: usize| {
111            selected.set(idx);
112        });
113
114        let on_sort = with!(sort_state => move |col: usize, asc: bool| {
115            sort_state.set(Some((col, asc)));
116        });
117
118        let on_activate = with!(selected => move |idx: usize| {
119            // In a real app, this might open a details view
120            selected.set(idx);
121        });
122
123        let selected_name = rows
124            .get(selected.get())
125            .and_then(|r| r.first())
126            .map(|s| s.as_str())
127            .unwrap_or("None");
128
129        let sort_info = match sort_state.get() {
130            Some((col, asc)) => {
131                let col_name = match col {
132                    0 => "NAME",
133                    1 => "STATUS",
134                    2 => "CPU",
135                    3 => "MEMORY",
136                    4 => "AGE",
137                    _ => "?",
138                };
139                format!(
140                    "Sorted by {} ({})",
141                    col_name,
142                    if asc { "asc" } else { "desc" }
143                )
144            }
145            None => "Unsorted".to_string(),
146        };
147
148        View::vstack()
149            .child(
150                View::styled_text("Pod Dashboard")
151                    .color(Color::Cyan)
152                    .bold()
153                    .build(),
154            )
155            .child(
156                View::styled_text(format!("Selected: {} | {}", selected_name, sort_info))
157                    .dim()
158                    .build(),
159            )
160            .child(
161                View::boxed()
162                    .flex(1)
163                    .border(true)
164                    .child(
165                        View::table()
166                            .column("NAME")
167                            .column_with(TableColumn::new("STATUS").width(ColumnWidth::Fixed(12)))
168                            .column_with(
169                                TableColumn::new("CPU")
170                                    .width(ColumnWidth::Fixed(8))
171                                    .align(TextAlign::Right),
172                            )
173                            .column_with(
174                                TableColumn::new("MEMORY")
175                                    .width(ColumnWidth::Fixed(10))
176                                    .align(TextAlign::Right),
177                            )
178                            .column_with(
179                                TableColumn::new("AGE")
180                                    .width(ColumnWidth::Fixed(8))
181                                    .align(TextAlign::Right),
182                            )
183                            .rows(rows)
184                            .selected(selected.get())
185                            .sort(sort_state.get())
186                            .on_select(on_select)
187                            .on_sort(on_sort)
188                            .on_activate(on_activate)
189                            .build(),
190                    )
191                    .build(),
192            )
193            .child(
194                View::styled_text("↑↓/jk: navigate | Enter: activate | F1 help | Ctrl+Q: quit")
195                    .dim()
196                    .build(),
197            )
198            .child(
199                View::modal()
200                    .visible(show_help.get())
201                    .title("Example 17: Table")
202                    .on_dismiss(with!(show_help => move || show_help.set(false)))
203                    .child(
204                        View::vstack()
205                            .child(View::styled_text("What you're seeing").bold().build())
206                            .child(View::text("• Data table with sortable columns"))
207                            .child(View::text("• Row selection and activation"))
208                            .child(View::text("• Fixed and flexible column widths"))
209                            .child(View::gap(1))
210                            .child(View::styled_text("Key concepts").bold().build())
211                            .child(View::text("• View::table() for tabular data"))
212                            .child(View::text("• TableColumn for column config"))
213                            .child(View::text("• ColumnWidth::Fixed or ColumnWidth::Flex"))
214                            .child(View::text("• on_sort callback for sorting"))
215                            .child(View::gap(1))
216                            .child(View::styled_text("Try this").bold().build())
217                            .child(View::text("• Navigate rows with arrow keys"))
218                            .child(View::text("• Press Enter to activate a row"))
219                            .child(View::text("• Sorting is managed via on_sort"))
220                            .child(View::gap(1))
221                            .child(View::styled_text("Next up").bold().build())
222                            .child(View::text("→ 18_progress_bar: progress indicators"))
223                            .child(View::gap(1))
224                            .child(View::styled_text("Press Escape to close").dim().build())
225                            .build(),
226                    )
227                    .build(),
228            )
229            .build()
230    }
Source

pub fn rows(self, rows: Vec<Vec<String>>) -> Self

Set the row data.

Examples found in repository?
examples/17_table.rs (line 183)
21    fn render(&self, cx: Scope) -> View {
22        let show_help = state!(cx, || false);
23
24        // F1 toggles help
25        cx.use_command(
26            KeyBinding::key(KeyCode::F(1)),
27            with!(show_help => move || show_help.update(|v| *v = !*v)),
28        );
29
30        // Track selected row
31        let selected = state!(cx, || 0usize);
32
33        // Track sort state (column index, ascending)
34        let sort_state = state!(cx, || None::<(usize, bool)>);
35
36        // Sample pod data (like k9s)
37        let base_data = vec![
38            vec![
39                "nginx-pod".to_string(),
40                "Running".to_string(),
41                "12%".to_string(),
42                "256Mi".to_string(),
43                "2h".to_string(),
44            ],
45            vec![
46                "redis-cache".to_string(),
47                "Running".to_string(),
48                "8%".to_string(),
49                "128Mi".to_string(),
50                "5d".to_string(),
51            ],
52            vec![
53                "api-server".to_string(),
54                "Running".to_string(),
55                "45%".to_string(),
56                "512Mi".to_string(),
57                "1h".to_string(),
58            ],
59            vec![
60                "db-postgres".to_string(),
61                "Running".to_string(),
62                "23%".to_string(),
63                "1Gi".to_string(),
64                "3d".to_string(),
65            ],
66            vec![
67                "worker-1".to_string(),
68                "Pending".to_string(),
69                "0%".to_string(),
70                "0Mi".to_string(),
71                "5m".to_string(),
72            ],
73            vec![
74                "worker-2".to_string(),
75                "Running".to_string(),
76                "67%".to_string(),
77                "384Mi".to_string(),
78                "45m".to_string(),
79            ],
80            vec![
81                "frontend".to_string(),
82                "Running".to_string(),
83                "5%".to_string(),
84                "64Mi".to_string(),
85                "12h".to_string(),
86            ],
87            vec![
88                "metrics".to_string(),
89                "CrashLoop".to_string(),
90                "0%".to_string(),
91                "32Mi".to_string(),
92                "2m".to_string(),
93            ],
94        ];
95
96        // Sort data based on current sort state
97        let mut rows = base_data.clone();
98        if let Some((col, ascending)) = sort_state.get() {
99            rows.sort_by(|a, b| {
100                let a_val = a.get(col).map(|s| s.as_str()).unwrap_or("");
101                let b_val = b.get(col).map(|s| s.as_str()).unwrap_or("");
102                if ascending {
103                    a_val.cmp(b_val)
104                } else {
105                    b_val.cmp(a_val)
106                }
107            });
108        }
109
110        let on_select = with!(selected => move |idx: usize| {
111            selected.set(idx);
112        });
113
114        let on_sort = with!(sort_state => move |col: usize, asc: bool| {
115            sort_state.set(Some((col, asc)));
116        });
117
118        let on_activate = with!(selected => move |idx: usize| {
119            // In a real app, this might open a details view
120            selected.set(idx);
121        });
122
123        let selected_name = rows
124            .get(selected.get())
125            .and_then(|r| r.first())
126            .map(|s| s.as_str())
127            .unwrap_or("None");
128
129        let sort_info = match sort_state.get() {
130            Some((col, asc)) => {
131                let col_name = match col {
132                    0 => "NAME",
133                    1 => "STATUS",
134                    2 => "CPU",
135                    3 => "MEMORY",
136                    4 => "AGE",
137                    _ => "?",
138                };
139                format!(
140                    "Sorted by {} ({})",
141                    col_name,
142                    if asc { "asc" } else { "desc" }
143                )
144            }
145            None => "Unsorted".to_string(),
146        };
147
148        View::vstack()
149            .child(
150                View::styled_text("Pod Dashboard")
151                    .color(Color::Cyan)
152                    .bold()
153                    .build(),
154            )
155            .child(
156                View::styled_text(format!("Selected: {} | {}", selected_name, sort_info))
157                    .dim()
158                    .build(),
159            )
160            .child(
161                View::boxed()
162                    .flex(1)
163                    .border(true)
164                    .child(
165                        View::table()
166                            .column("NAME")
167                            .column_with(TableColumn::new("STATUS").width(ColumnWidth::Fixed(12)))
168                            .column_with(
169                                TableColumn::new("CPU")
170                                    .width(ColumnWidth::Fixed(8))
171                                    .align(TextAlign::Right),
172                            )
173                            .column_with(
174                                TableColumn::new("MEMORY")
175                                    .width(ColumnWidth::Fixed(10))
176                                    .align(TextAlign::Right),
177                            )
178                            .column_with(
179                                TableColumn::new("AGE")
180                                    .width(ColumnWidth::Fixed(8))
181                                    .align(TextAlign::Right),
182                            )
183                            .rows(rows)
184                            .selected(selected.get())
185                            .sort(sort_state.get())
186                            .on_select(on_select)
187                            .on_sort(on_sort)
188                            .on_activate(on_activate)
189                            .build(),
190                    )
191                    .build(),
192            )
193            .child(
194                View::styled_text("↑↓/jk: navigate | Enter: activate | F1 help | Ctrl+Q: quit")
195                    .dim()
196                    .build(),
197            )
198            .child(
199                View::modal()
200                    .visible(show_help.get())
201                    .title("Example 17: Table")
202                    .on_dismiss(with!(show_help => move || show_help.set(false)))
203                    .child(
204                        View::vstack()
205                            .child(View::styled_text("What you're seeing").bold().build())
206                            .child(View::text("• Data table with sortable columns"))
207                            .child(View::text("• Row selection and activation"))
208                            .child(View::text("• Fixed and flexible column widths"))
209                            .child(View::gap(1))
210                            .child(View::styled_text("Key concepts").bold().build())
211                            .child(View::text("• View::table() for tabular data"))
212                            .child(View::text("• TableColumn for column config"))
213                            .child(View::text("• ColumnWidth::Fixed or ColumnWidth::Flex"))
214                            .child(View::text("• on_sort callback for sorting"))
215                            .child(View::gap(1))
216                            .child(View::styled_text("Try this").bold().build())
217                            .child(View::text("• Navigate rows with arrow keys"))
218                            .child(View::text("• Press Enter to activate a row"))
219                            .child(View::text("• Sorting is managed via on_sort"))
220                            .child(View::gap(1))
221                            .child(View::styled_text("Next up").bold().build())
222                            .child(View::text("→ 18_progress_bar: progress indicators"))
223                            .child(View::gap(1))
224                            .child(View::styled_text("Press Escape to close").dim().build())
225                            .build(),
226                    )
227                    .build(),
228            )
229            .build()
230    }
Source

pub fn row(self, row: Vec<String>) -> Self

Add a single row.

Source

pub fn selected(self, index: usize) -> Self

Set the selected row index.

Examples found in repository?
examples/17_table.rs (line 184)
21    fn render(&self, cx: Scope) -> View {
22        let show_help = state!(cx, || false);
23
24        // F1 toggles help
25        cx.use_command(
26            KeyBinding::key(KeyCode::F(1)),
27            with!(show_help => move || show_help.update(|v| *v = !*v)),
28        );
29
30        // Track selected row
31        let selected = state!(cx, || 0usize);
32
33        // Track sort state (column index, ascending)
34        let sort_state = state!(cx, || None::<(usize, bool)>);
35
36        // Sample pod data (like k9s)
37        let base_data = vec![
38            vec![
39                "nginx-pod".to_string(),
40                "Running".to_string(),
41                "12%".to_string(),
42                "256Mi".to_string(),
43                "2h".to_string(),
44            ],
45            vec![
46                "redis-cache".to_string(),
47                "Running".to_string(),
48                "8%".to_string(),
49                "128Mi".to_string(),
50                "5d".to_string(),
51            ],
52            vec![
53                "api-server".to_string(),
54                "Running".to_string(),
55                "45%".to_string(),
56                "512Mi".to_string(),
57                "1h".to_string(),
58            ],
59            vec![
60                "db-postgres".to_string(),
61                "Running".to_string(),
62                "23%".to_string(),
63                "1Gi".to_string(),
64                "3d".to_string(),
65            ],
66            vec![
67                "worker-1".to_string(),
68                "Pending".to_string(),
69                "0%".to_string(),
70                "0Mi".to_string(),
71                "5m".to_string(),
72            ],
73            vec![
74                "worker-2".to_string(),
75                "Running".to_string(),
76                "67%".to_string(),
77                "384Mi".to_string(),
78                "45m".to_string(),
79            ],
80            vec![
81                "frontend".to_string(),
82                "Running".to_string(),
83                "5%".to_string(),
84                "64Mi".to_string(),
85                "12h".to_string(),
86            ],
87            vec![
88                "metrics".to_string(),
89                "CrashLoop".to_string(),
90                "0%".to_string(),
91                "32Mi".to_string(),
92                "2m".to_string(),
93            ],
94        ];
95
96        // Sort data based on current sort state
97        let mut rows = base_data.clone();
98        if let Some((col, ascending)) = sort_state.get() {
99            rows.sort_by(|a, b| {
100                let a_val = a.get(col).map(|s| s.as_str()).unwrap_or("");
101                let b_val = b.get(col).map(|s| s.as_str()).unwrap_or("");
102                if ascending {
103                    a_val.cmp(b_val)
104                } else {
105                    b_val.cmp(a_val)
106                }
107            });
108        }
109
110        let on_select = with!(selected => move |idx: usize| {
111            selected.set(idx);
112        });
113
114        let on_sort = with!(sort_state => move |col: usize, asc: bool| {
115            sort_state.set(Some((col, asc)));
116        });
117
118        let on_activate = with!(selected => move |idx: usize| {
119            // In a real app, this might open a details view
120            selected.set(idx);
121        });
122
123        let selected_name = rows
124            .get(selected.get())
125            .and_then(|r| r.first())
126            .map(|s| s.as_str())
127            .unwrap_or("None");
128
129        let sort_info = match sort_state.get() {
130            Some((col, asc)) => {
131                let col_name = match col {
132                    0 => "NAME",
133                    1 => "STATUS",
134                    2 => "CPU",
135                    3 => "MEMORY",
136                    4 => "AGE",
137                    _ => "?",
138                };
139                format!(
140                    "Sorted by {} ({})",
141                    col_name,
142                    if asc { "asc" } else { "desc" }
143                )
144            }
145            None => "Unsorted".to_string(),
146        };
147
148        View::vstack()
149            .child(
150                View::styled_text("Pod Dashboard")
151                    .color(Color::Cyan)
152                    .bold()
153                    .build(),
154            )
155            .child(
156                View::styled_text(format!("Selected: {} | {}", selected_name, sort_info))
157                    .dim()
158                    .build(),
159            )
160            .child(
161                View::boxed()
162                    .flex(1)
163                    .border(true)
164                    .child(
165                        View::table()
166                            .column("NAME")
167                            .column_with(TableColumn::new("STATUS").width(ColumnWidth::Fixed(12)))
168                            .column_with(
169                                TableColumn::new("CPU")
170                                    .width(ColumnWidth::Fixed(8))
171                                    .align(TextAlign::Right),
172                            )
173                            .column_with(
174                                TableColumn::new("MEMORY")
175                                    .width(ColumnWidth::Fixed(10))
176                                    .align(TextAlign::Right),
177                            )
178                            .column_with(
179                                TableColumn::new("AGE")
180                                    .width(ColumnWidth::Fixed(8))
181                                    .align(TextAlign::Right),
182                            )
183                            .rows(rows)
184                            .selected(selected.get())
185                            .sort(sort_state.get())
186                            .on_select(on_select)
187                            .on_sort(on_sort)
188                            .on_activate(on_activate)
189                            .build(),
190                    )
191                    .build(),
192            )
193            .child(
194                View::styled_text("↑↓/jk: navigate | Enter: activate | F1 help | Ctrl+Q: quit")
195                    .dim()
196                    .build(),
197            )
198            .child(
199                View::modal()
200                    .visible(show_help.get())
201                    .title("Example 17: Table")
202                    .on_dismiss(with!(show_help => move || show_help.set(false)))
203                    .child(
204                        View::vstack()
205                            .child(View::styled_text("What you're seeing").bold().build())
206                            .child(View::text("• Data table with sortable columns"))
207                            .child(View::text("• Row selection and activation"))
208                            .child(View::text("• Fixed and flexible column widths"))
209                            .child(View::gap(1))
210                            .child(View::styled_text("Key concepts").bold().build())
211                            .child(View::text("• View::table() for tabular data"))
212                            .child(View::text("• TableColumn for column config"))
213                            .child(View::text("• ColumnWidth::Fixed or ColumnWidth::Flex"))
214                            .child(View::text("• on_sort callback for sorting"))
215                            .child(View::gap(1))
216                            .child(View::styled_text("Try this").bold().build())
217                            .child(View::text("• Navigate rows with arrow keys"))
218                            .child(View::text("• Press Enter to activate a row"))
219                            .child(View::text("• Sorting is managed via on_sort"))
220                            .child(View::gap(1))
221                            .child(View::styled_text("Next up").bold().build())
222                            .child(View::text("→ 18_progress_bar: progress indicators"))
223                            .child(View::gap(1))
224                            .child(View::styled_text("Press Escape to close").dim().build())
225                            .build(),
226                    )
227                    .build(),
228            )
229            .build()
230    }
Source

pub fn sort(self, sort: Option<(usize, bool)>) -> Self

Set the sort state (column index, ascending).

Examples found in repository?
examples/17_table.rs (line 185)
21    fn render(&self, cx: Scope) -> View {
22        let show_help = state!(cx, || false);
23
24        // F1 toggles help
25        cx.use_command(
26            KeyBinding::key(KeyCode::F(1)),
27            with!(show_help => move || show_help.update(|v| *v = !*v)),
28        );
29
30        // Track selected row
31        let selected = state!(cx, || 0usize);
32
33        // Track sort state (column index, ascending)
34        let sort_state = state!(cx, || None::<(usize, bool)>);
35
36        // Sample pod data (like k9s)
37        let base_data = vec![
38            vec![
39                "nginx-pod".to_string(),
40                "Running".to_string(),
41                "12%".to_string(),
42                "256Mi".to_string(),
43                "2h".to_string(),
44            ],
45            vec![
46                "redis-cache".to_string(),
47                "Running".to_string(),
48                "8%".to_string(),
49                "128Mi".to_string(),
50                "5d".to_string(),
51            ],
52            vec![
53                "api-server".to_string(),
54                "Running".to_string(),
55                "45%".to_string(),
56                "512Mi".to_string(),
57                "1h".to_string(),
58            ],
59            vec![
60                "db-postgres".to_string(),
61                "Running".to_string(),
62                "23%".to_string(),
63                "1Gi".to_string(),
64                "3d".to_string(),
65            ],
66            vec![
67                "worker-1".to_string(),
68                "Pending".to_string(),
69                "0%".to_string(),
70                "0Mi".to_string(),
71                "5m".to_string(),
72            ],
73            vec![
74                "worker-2".to_string(),
75                "Running".to_string(),
76                "67%".to_string(),
77                "384Mi".to_string(),
78                "45m".to_string(),
79            ],
80            vec![
81                "frontend".to_string(),
82                "Running".to_string(),
83                "5%".to_string(),
84                "64Mi".to_string(),
85                "12h".to_string(),
86            ],
87            vec![
88                "metrics".to_string(),
89                "CrashLoop".to_string(),
90                "0%".to_string(),
91                "32Mi".to_string(),
92                "2m".to_string(),
93            ],
94        ];
95
96        // Sort data based on current sort state
97        let mut rows = base_data.clone();
98        if let Some((col, ascending)) = sort_state.get() {
99            rows.sort_by(|a, b| {
100                let a_val = a.get(col).map(|s| s.as_str()).unwrap_or("");
101                let b_val = b.get(col).map(|s| s.as_str()).unwrap_or("");
102                if ascending {
103                    a_val.cmp(b_val)
104                } else {
105                    b_val.cmp(a_val)
106                }
107            });
108        }
109
110        let on_select = with!(selected => move |idx: usize| {
111            selected.set(idx);
112        });
113
114        let on_sort = with!(sort_state => move |col: usize, asc: bool| {
115            sort_state.set(Some((col, asc)));
116        });
117
118        let on_activate = with!(selected => move |idx: usize| {
119            // In a real app, this might open a details view
120            selected.set(idx);
121        });
122
123        let selected_name = rows
124            .get(selected.get())
125            .and_then(|r| r.first())
126            .map(|s| s.as_str())
127            .unwrap_or("None");
128
129        let sort_info = match sort_state.get() {
130            Some((col, asc)) => {
131                let col_name = match col {
132                    0 => "NAME",
133                    1 => "STATUS",
134                    2 => "CPU",
135                    3 => "MEMORY",
136                    4 => "AGE",
137                    _ => "?",
138                };
139                format!(
140                    "Sorted by {} ({})",
141                    col_name,
142                    if asc { "asc" } else { "desc" }
143                )
144            }
145            None => "Unsorted".to_string(),
146        };
147
148        View::vstack()
149            .child(
150                View::styled_text("Pod Dashboard")
151                    .color(Color::Cyan)
152                    .bold()
153                    .build(),
154            )
155            .child(
156                View::styled_text(format!("Selected: {} | {}", selected_name, sort_info))
157                    .dim()
158                    .build(),
159            )
160            .child(
161                View::boxed()
162                    .flex(1)
163                    .border(true)
164                    .child(
165                        View::table()
166                            .column("NAME")
167                            .column_with(TableColumn::new("STATUS").width(ColumnWidth::Fixed(12)))
168                            .column_with(
169                                TableColumn::new("CPU")
170                                    .width(ColumnWidth::Fixed(8))
171                                    .align(TextAlign::Right),
172                            )
173                            .column_with(
174                                TableColumn::new("MEMORY")
175                                    .width(ColumnWidth::Fixed(10))
176                                    .align(TextAlign::Right),
177                            )
178                            .column_with(
179                                TableColumn::new("AGE")
180                                    .width(ColumnWidth::Fixed(8))
181                                    .align(TextAlign::Right),
182                            )
183                            .rows(rows)
184                            .selected(selected.get())
185                            .sort(sort_state.get())
186                            .on_select(on_select)
187                            .on_sort(on_sort)
188                            .on_activate(on_activate)
189                            .build(),
190                    )
191                    .build(),
192            )
193            .child(
194                View::styled_text("↑↓/jk: navigate | Enter: activate | F1 help | Ctrl+Q: quit")
195                    .dim()
196                    .build(),
197            )
198            .child(
199                View::modal()
200                    .visible(show_help.get())
201                    .title("Example 17: Table")
202                    .on_dismiss(with!(show_help => move || show_help.set(false)))
203                    .child(
204                        View::vstack()
205                            .child(View::styled_text("What you're seeing").bold().build())
206                            .child(View::text("• Data table with sortable columns"))
207                            .child(View::text("• Row selection and activation"))
208                            .child(View::text("• Fixed and flexible column widths"))
209                            .child(View::gap(1))
210                            .child(View::styled_text("Key concepts").bold().build())
211                            .child(View::text("• View::table() for tabular data"))
212                            .child(View::text("• TableColumn for column config"))
213                            .child(View::text("• ColumnWidth::Fixed or ColumnWidth::Flex"))
214                            .child(View::text("• on_sort callback for sorting"))
215                            .child(View::gap(1))
216                            .child(View::styled_text("Try this").bold().build())
217                            .child(View::text("• Navigate rows with arrow keys"))
218                            .child(View::text("• Press Enter to activate a row"))
219                            .child(View::text("• Sorting is managed via on_sort"))
220                            .child(View::gap(1))
221                            .child(View::styled_text("Next up").bold().build())
222                            .child(View::text("→ 18_progress_bar: progress indicators"))
223                            .child(View::gap(1))
224                            .child(View::styled_text("Press Escape to close").dim().build())
225                            .build(),
226                    )
227                    .build(),
228            )
229            .build()
230    }
Source

pub fn sort_by(self, column: usize, ascending: bool) -> Self

Set the sort state with explicit column and direction.

Source

pub fn on_select(self, callback: impl Fn(usize) + 'static) -> Self

Set the callback when selection changes.

Examples found in repository?
examples/17_table.rs (line 186)
21    fn render(&self, cx: Scope) -> View {
22        let show_help = state!(cx, || false);
23
24        // F1 toggles help
25        cx.use_command(
26            KeyBinding::key(KeyCode::F(1)),
27            with!(show_help => move || show_help.update(|v| *v = !*v)),
28        );
29
30        // Track selected row
31        let selected = state!(cx, || 0usize);
32
33        // Track sort state (column index, ascending)
34        let sort_state = state!(cx, || None::<(usize, bool)>);
35
36        // Sample pod data (like k9s)
37        let base_data = vec![
38            vec![
39                "nginx-pod".to_string(),
40                "Running".to_string(),
41                "12%".to_string(),
42                "256Mi".to_string(),
43                "2h".to_string(),
44            ],
45            vec![
46                "redis-cache".to_string(),
47                "Running".to_string(),
48                "8%".to_string(),
49                "128Mi".to_string(),
50                "5d".to_string(),
51            ],
52            vec![
53                "api-server".to_string(),
54                "Running".to_string(),
55                "45%".to_string(),
56                "512Mi".to_string(),
57                "1h".to_string(),
58            ],
59            vec![
60                "db-postgres".to_string(),
61                "Running".to_string(),
62                "23%".to_string(),
63                "1Gi".to_string(),
64                "3d".to_string(),
65            ],
66            vec![
67                "worker-1".to_string(),
68                "Pending".to_string(),
69                "0%".to_string(),
70                "0Mi".to_string(),
71                "5m".to_string(),
72            ],
73            vec![
74                "worker-2".to_string(),
75                "Running".to_string(),
76                "67%".to_string(),
77                "384Mi".to_string(),
78                "45m".to_string(),
79            ],
80            vec![
81                "frontend".to_string(),
82                "Running".to_string(),
83                "5%".to_string(),
84                "64Mi".to_string(),
85                "12h".to_string(),
86            ],
87            vec![
88                "metrics".to_string(),
89                "CrashLoop".to_string(),
90                "0%".to_string(),
91                "32Mi".to_string(),
92                "2m".to_string(),
93            ],
94        ];
95
96        // Sort data based on current sort state
97        let mut rows = base_data.clone();
98        if let Some((col, ascending)) = sort_state.get() {
99            rows.sort_by(|a, b| {
100                let a_val = a.get(col).map(|s| s.as_str()).unwrap_or("");
101                let b_val = b.get(col).map(|s| s.as_str()).unwrap_or("");
102                if ascending {
103                    a_val.cmp(b_val)
104                } else {
105                    b_val.cmp(a_val)
106                }
107            });
108        }
109
110        let on_select = with!(selected => move |idx: usize| {
111            selected.set(idx);
112        });
113
114        let on_sort = with!(sort_state => move |col: usize, asc: bool| {
115            sort_state.set(Some((col, asc)));
116        });
117
118        let on_activate = with!(selected => move |idx: usize| {
119            // In a real app, this might open a details view
120            selected.set(idx);
121        });
122
123        let selected_name = rows
124            .get(selected.get())
125            .and_then(|r| r.first())
126            .map(|s| s.as_str())
127            .unwrap_or("None");
128
129        let sort_info = match sort_state.get() {
130            Some((col, asc)) => {
131                let col_name = match col {
132                    0 => "NAME",
133                    1 => "STATUS",
134                    2 => "CPU",
135                    3 => "MEMORY",
136                    4 => "AGE",
137                    _ => "?",
138                };
139                format!(
140                    "Sorted by {} ({})",
141                    col_name,
142                    if asc { "asc" } else { "desc" }
143                )
144            }
145            None => "Unsorted".to_string(),
146        };
147
148        View::vstack()
149            .child(
150                View::styled_text("Pod Dashboard")
151                    .color(Color::Cyan)
152                    .bold()
153                    .build(),
154            )
155            .child(
156                View::styled_text(format!("Selected: {} | {}", selected_name, sort_info))
157                    .dim()
158                    .build(),
159            )
160            .child(
161                View::boxed()
162                    .flex(1)
163                    .border(true)
164                    .child(
165                        View::table()
166                            .column("NAME")
167                            .column_with(TableColumn::new("STATUS").width(ColumnWidth::Fixed(12)))
168                            .column_with(
169                                TableColumn::new("CPU")
170                                    .width(ColumnWidth::Fixed(8))
171                                    .align(TextAlign::Right),
172                            )
173                            .column_with(
174                                TableColumn::new("MEMORY")
175                                    .width(ColumnWidth::Fixed(10))
176                                    .align(TextAlign::Right),
177                            )
178                            .column_with(
179                                TableColumn::new("AGE")
180                                    .width(ColumnWidth::Fixed(8))
181                                    .align(TextAlign::Right),
182                            )
183                            .rows(rows)
184                            .selected(selected.get())
185                            .sort(sort_state.get())
186                            .on_select(on_select)
187                            .on_sort(on_sort)
188                            .on_activate(on_activate)
189                            .build(),
190                    )
191                    .build(),
192            )
193            .child(
194                View::styled_text("↑↓/jk: navigate | Enter: activate | F1 help | Ctrl+Q: quit")
195                    .dim()
196                    .build(),
197            )
198            .child(
199                View::modal()
200                    .visible(show_help.get())
201                    .title("Example 17: Table")
202                    .on_dismiss(with!(show_help => move || show_help.set(false)))
203                    .child(
204                        View::vstack()
205                            .child(View::styled_text("What you're seeing").bold().build())
206                            .child(View::text("• Data table with sortable columns"))
207                            .child(View::text("• Row selection and activation"))
208                            .child(View::text("• Fixed and flexible column widths"))
209                            .child(View::gap(1))
210                            .child(View::styled_text("Key concepts").bold().build())
211                            .child(View::text("• View::table() for tabular data"))
212                            .child(View::text("• TableColumn for column config"))
213                            .child(View::text("• ColumnWidth::Fixed or ColumnWidth::Flex"))
214                            .child(View::text("• on_sort callback for sorting"))
215                            .child(View::gap(1))
216                            .child(View::styled_text("Try this").bold().build())
217                            .child(View::text("• Navigate rows with arrow keys"))
218                            .child(View::text("• Press Enter to activate a row"))
219                            .child(View::text("• Sorting is managed via on_sort"))
220                            .child(View::gap(1))
221                            .child(View::styled_text("Next up").bold().build())
222                            .child(View::text("→ 18_progress_bar: progress indicators"))
223                            .child(View::gap(1))
224                            .child(View::styled_text("Press Escape to close").dim().build())
225                            .build(),
226                    )
227                    .build(),
228            )
229            .build()
230    }
Source

pub fn on_sort(self, callback: impl Fn(usize, bool) + 'static) -> Self

Set the callback when sort changes.

Examples found in repository?
examples/17_table.rs (line 187)
21    fn render(&self, cx: Scope) -> View {
22        let show_help = state!(cx, || false);
23
24        // F1 toggles help
25        cx.use_command(
26            KeyBinding::key(KeyCode::F(1)),
27            with!(show_help => move || show_help.update(|v| *v = !*v)),
28        );
29
30        // Track selected row
31        let selected = state!(cx, || 0usize);
32
33        // Track sort state (column index, ascending)
34        let sort_state = state!(cx, || None::<(usize, bool)>);
35
36        // Sample pod data (like k9s)
37        let base_data = vec![
38            vec![
39                "nginx-pod".to_string(),
40                "Running".to_string(),
41                "12%".to_string(),
42                "256Mi".to_string(),
43                "2h".to_string(),
44            ],
45            vec![
46                "redis-cache".to_string(),
47                "Running".to_string(),
48                "8%".to_string(),
49                "128Mi".to_string(),
50                "5d".to_string(),
51            ],
52            vec![
53                "api-server".to_string(),
54                "Running".to_string(),
55                "45%".to_string(),
56                "512Mi".to_string(),
57                "1h".to_string(),
58            ],
59            vec![
60                "db-postgres".to_string(),
61                "Running".to_string(),
62                "23%".to_string(),
63                "1Gi".to_string(),
64                "3d".to_string(),
65            ],
66            vec![
67                "worker-1".to_string(),
68                "Pending".to_string(),
69                "0%".to_string(),
70                "0Mi".to_string(),
71                "5m".to_string(),
72            ],
73            vec![
74                "worker-2".to_string(),
75                "Running".to_string(),
76                "67%".to_string(),
77                "384Mi".to_string(),
78                "45m".to_string(),
79            ],
80            vec![
81                "frontend".to_string(),
82                "Running".to_string(),
83                "5%".to_string(),
84                "64Mi".to_string(),
85                "12h".to_string(),
86            ],
87            vec![
88                "metrics".to_string(),
89                "CrashLoop".to_string(),
90                "0%".to_string(),
91                "32Mi".to_string(),
92                "2m".to_string(),
93            ],
94        ];
95
96        // Sort data based on current sort state
97        let mut rows = base_data.clone();
98        if let Some((col, ascending)) = sort_state.get() {
99            rows.sort_by(|a, b| {
100                let a_val = a.get(col).map(|s| s.as_str()).unwrap_or("");
101                let b_val = b.get(col).map(|s| s.as_str()).unwrap_or("");
102                if ascending {
103                    a_val.cmp(b_val)
104                } else {
105                    b_val.cmp(a_val)
106                }
107            });
108        }
109
110        let on_select = with!(selected => move |idx: usize| {
111            selected.set(idx);
112        });
113
114        let on_sort = with!(sort_state => move |col: usize, asc: bool| {
115            sort_state.set(Some((col, asc)));
116        });
117
118        let on_activate = with!(selected => move |idx: usize| {
119            // In a real app, this might open a details view
120            selected.set(idx);
121        });
122
123        let selected_name = rows
124            .get(selected.get())
125            .and_then(|r| r.first())
126            .map(|s| s.as_str())
127            .unwrap_or("None");
128
129        let sort_info = match sort_state.get() {
130            Some((col, asc)) => {
131                let col_name = match col {
132                    0 => "NAME",
133                    1 => "STATUS",
134                    2 => "CPU",
135                    3 => "MEMORY",
136                    4 => "AGE",
137                    _ => "?",
138                };
139                format!(
140                    "Sorted by {} ({})",
141                    col_name,
142                    if asc { "asc" } else { "desc" }
143                )
144            }
145            None => "Unsorted".to_string(),
146        };
147
148        View::vstack()
149            .child(
150                View::styled_text("Pod Dashboard")
151                    .color(Color::Cyan)
152                    .bold()
153                    .build(),
154            )
155            .child(
156                View::styled_text(format!("Selected: {} | {}", selected_name, sort_info))
157                    .dim()
158                    .build(),
159            )
160            .child(
161                View::boxed()
162                    .flex(1)
163                    .border(true)
164                    .child(
165                        View::table()
166                            .column("NAME")
167                            .column_with(TableColumn::new("STATUS").width(ColumnWidth::Fixed(12)))
168                            .column_with(
169                                TableColumn::new("CPU")
170                                    .width(ColumnWidth::Fixed(8))
171                                    .align(TextAlign::Right),
172                            )
173                            .column_with(
174                                TableColumn::new("MEMORY")
175                                    .width(ColumnWidth::Fixed(10))
176                                    .align(TextAlign::Right),
177                            )
178                            .column_with(
179                                TableColumn::new("AGE")
180                                    .width(ColumnWidth::Fixed(8))
181                                    .align(TextAlign::Right),
182                            )
183                            .rows(rows)
184                            .selected(selected.get())
185                            .sort(sort_state.get())
186                            .on_select(on_select)
187                            .on_sort(on_sort)
188                            .on_activate(on_activate)
189                            .build(),
190                    )
191                    .build(),
192            )
193            .child(
194                View::styled_text("↑↓/jk: navigate | Enter: activate | F1 help | Ctrl+Q: quit")
195                    .dim()
196                    .build(),
197            )
198            .child(
199                View::modal()
200                    .visible(show_help.get())
201                    .title("Example 17: Table")
202                    .on_dismiss(with!(show_help => move || show_help.set(false)))
203                    .child(
204                        View::vstack()
205                            .child(View::styled_text("What you're seeing").bold().build())
206                            .child(View::text("• Data table with sortable columns"))
207                            .child(View::text("• Row selection and activation"))
208                            .child(View::text("• Fixed and flexible column widths"))
209                            .child(View::gap(1))
210                            .child(View::styled_text("Key concepts").bold().build())
211                            .child(View::text("• View::table() for tabular data"))
212                            .child(View::text("• TableColumn for column config"))
213                            .child(View::text("• ColumnWidth::Fixed or ColumnWidth::Flex"))
214                            .child(View::text("• on_sort callback for sorting"))
215                            .child(View::gap(1))
216                            .child(View::styled_text("Try this").bold().build())
217                            .child(View::text("• Navigate rows with arrow keys"))
218                            .child(View::text("• Press Enter to activate a row"))
219                            .child(View::text("• Sorting is managed via on_sort"))
220                            .child(View::gap(1))
221                            .child(View::styled_text("Next up").bold().build())
222                            .child(View::text("→ 18_progress_bar: progress indicators"))
223                            .child(View::gap(1))
224                            .child(View::styled_text("Press Escape to close").dim().build())
225                            .build(),
226                    )
227                    .build(),
228            )
229            .build()
230    }
Source

pub fn on_activate(self, callback: impl Fn(usize) + 'static) -> Self

Set the callback when a row is activated.

Examples found in repository?
examples/17_table.rs (line 188)
21    fn render(&self, cx: Scope) -> View {
22        let show_help = state!(cx, || false);
23
24        // F1 toggles help
25        cx.use_command(
26            KeyBinding::key(KeyCode::F(1)),
27            with!(show_help => move || show_help.update(|v| *v = !*v)),
28        );
29
30        // Track selected row
31        let selected = state!(cx, || 0usize);
32
33        // Track sort state (column index, ascending)
34        let sort_state = state!(cx, || None::<(usize, bool)>);
35
36        // Sample pod data (like k9s)
37        let base_data = vec![
38            vec![
39                "nginx-pod".to_string(),
40                "Running".to_string(),
41                "12%".to_string(),
42                "256Mi".to_string(),
43                "2h".to_string(),
44            ],
45            vec![
46                "redis-cache".to_string(),
47                "Running".to_string(),
48                "8%".to_string(),
49                "128Mi".to_string(),
50                "5d".to_string(),
51            ],
52            vec![
53                "api-server".to_string(),
54                "Running".to_string(),
55                "45%".to_string(),
56                "512Mi".to_string(),
57                "1h".to_string(),
58            ],
59            vec![
60                "db-postgres".to_string(),
61                "Running".to_string(),
62                "23%".to_string(),
63                "1Gi".to_string(),
64                "3d".to_string(),
65            ],
66            vec![
67                "worker-1".to_string(),
68                "Pending".to_string(),
69                "0%".to_string(),
70                "0Mi".to_string(),
71                "5m".to_string(),
72            ],
73            vec![
74                "worker-2".to_string(),
75                "Running".to_string(),
76                "67%".to_string(),
77                "384Mi".to_string(),
78                "45m".to_string(),
79            ],
80            vec![
81                "frontend".to_string(),
82                "Running".to_string(),
83                "5%".to_string(),
84                "64Mi".to_string(),
85                "12h".to_string(),
86            ],
87            vec![
88                "metrics".to_string(),
89                "CrashLoop".to_string(),
90                "0%".to_string(),
91                "32Mi".to_string(),
92                "2m".to_string(),
93            ],
94        ];
95
96        // Sort data based on current sort state
97        let mut rows = base_data.clone();
98        if let Some((col, ascending)) = sort_state.get() {
99            rows.sort_by(|a, b| {
100                let a_val = a.get(col).map(|s| s.as_str()).unwrap_or("");
101                let b_val = b.get(col).map(|s| s.as_str()).unwrap_or("");
102                if ascending {
103                    a_val.cmp(b_val)
104                } else {
105                    b_val.cmp(a_val)
106                }
107            });
108        }
109
110        let on_select = with!(selected => move |idx: usize| {
111            selected.set(idx);
112        });
113
114        let on_sort = with!(sort_state => move |col: usize, asc: bool| {
115            sort_state.set(Some((col, asc)));
116        });
117
118        let on_activate = with!(selected => move |idx: usize| {
119            // In a real app, this might open a details view
120            selected.set(idx);
121        });
122
123        let selected_name = rows
124            .get(selected.get())
125            .and_then(|r| r.first())
126            .map(|s| s.as_str())
127            .unwrap_or("None");
128
129        let sort_info = match sort_state.get() {
130            Some((col, asc)) => {
131                let col_name = match col {
132                    0 => "NAME",
133                    1 => "STATUS",
134                    2 => "CPU",
135                    3 => "MEMORY",
136                    4 => "AGE",
137                    _ => "?",
138                };
139                format!(
140                    "Sorted by {} ({})",
141                    col_name,
142                    if asc { "asc" } else { "desc" }
143                )
144            }
145            None => "Unsorted".to_string(),
146        };
147
148        View::vstack()
149            .child(
150                View::styled_text("Pod Dashboard")
151                    .color(Color::Cyan)
152                    .bold()
153                    .build(),
154            )
155            .child(
156                View::styled_text(format!("Selected: {} | {}", selected_name, sort_info))
157                    .dim()
158                    .build(),
159            )
160            .child(
161                View::boxed()
162                    .flex(1)
163                    .border(true)
164                    .child(
165                        View::table()
166                            .column("NAME")
167                            .column_with(TableColumn::new("STATUS").width(ColumnWidth::Fixed(12)))
168                            .column_with(
169                                TableColumn::new("CPU")
170                                    .width(ColumnWidth::Fixed(8))
171                                    .align(TextAlign::Right),
172                            )
173                            .column_with(
174                                TableColumn::new("MEMORY")
175                                    .width(ColumnWidth::Fixed(10))
176                                    .align(TextAlign::Right),
177                            )
178                            .column_with(
179                                TableColumn::new("AGE")
180                                    .width(ColumnWidth::Fixed(8))
181                                    .align(TextAlign::Right),
182                            )
183                            .rows(rows)
184                            .selected(selected.get())
185                            .sort(sort_state.get())
186                            .on_select(on_select)
187                            .on_sort(on_sort)
188                            .on_activate(on_activate)
189                            .build(),
190                    )
191                    .build(),
192            )
193            .child(
194                View::styled_text("↑↓/jk: navigate | Enter: activate | F1 help | Ctrl+Q: quit")
195                    .dim()
196                    .build(),
197            )
198            .child(
199                View::modal()
200                    .visible(show_help.get())
201                    .title("Example 17: Table")
202                    .on_dismiss(with!(show_help => move || show_help.set(false)))
203                    .child(
204                        View::vstack()
205                            .child(View::styled_text("What you're seeing").bold().build())
206                            .child(View::text("• Data table with sortable columns"))
207                            .child(View::text("• Row selection and activation"))
208                            .child(View::text("• Fixed and flexible column widths"))
209                            .child(View::gap(1))
210                            .child(View::styled_text("Key concepts").bold().build())
211                            .child(View::text("• View::table() for tabular data"))
212                            .child(View::text("• TableColumn for column config"))
213                            .child(View::text("• ColumnWidth::Fixed or ColumnWidth::Flex"))
214                            .child(View::text("• on_sort callback for sorting"))
215                            .child(View::gap(1))
216                            .child(View::styled_text("Try this").bold().build())
217                            .child(View::text("• Navigate rows with arrow keys"))
218                            .child(View::text("• Press Enter to activate a row"))
219                            .child(View::text("• Sorting is managed via on_sort"))
220                            .child(View::gap(1))
221                            .child(View::styled_text("Next up").bold().build())
222                            .child(View::text("→ 18_progress_bar: progress indicators"))
223                            .child(View::gap(1))
224                            .child(View::styled_text("Press Escape to close").dim().build())
225                            .build(),
226                    )
227                    .build(),
228            )
229            .build()
230    }
Source

pub fn build(self) -> View

Examples found in repository?
examples/17_table.rs (line 189)
21    fn render(&self, cx: Scope) -> View {
22        let show_help = state!(cx, || false);
23
24        // F1 toggles help
25        cx.use_command(
26            KeyBinding::key(KeyCode::F(1)),
27            with!(show_help => move || show_help.update(|v| *v = !*v)),
28        );
29
30        // Track selected row
31        let selected = state!(cx, || 0usize);
32
33        // Track sort state (column index, ascending)
34        let sort_state = state!(cx, || None::<(usize, bool)>);
35
36        // Sample pod data (like k9s)
37        let base_data = vec![
38            vec![
39                "nginx-pod".to_string(),
40                "Running".to_string(),
41                "12%".to_string(),
42                "256Mi".to_string(),
43                "2h".to_string(),
44            ],
45            vec![
46                "redis-cache".to_string(),
47                "Running".to_string(),
48                "8%".to_string(),
49                "128Mi".to_string(),
50                "5d".to_string(),
51            ],
52            vec![
53                "api-server".to_string(),
54                "Running".to_string(),
55                "45%".to_string(),
56                "512Mi".to_string(),
57                "1h".to_string(),
58            ],
59            vec![
60                "db-postgres".to_string(),
61                "Running".to_string(),
62                "23%".to_string(),
63                "1Gi".to_string(),
64                "3d".to_string(),
65            ],
66            vec![
67                "worker-1".to_string(),
68                "Pending".to_string(),
69                "0%".to_string(),
70                "0Mi".to_string(),
71                "5m".to_string(),
72            ],
73            vec![
74                "worker-2".to_string(),
75                "Running".to_string(),
76                "67%".to_string(),
77                "384Mi".to_string(),
78                "45m".to_string(),
79            ],
80            vec![
81                "frontend".to_string(),
82                "Running".to_string(),
83                "5%".to_string(),
84                "64Mi".to_string(),
85                "12h".to_string(),
86            ],
87            vec![
88                "metrics".to_string(),
89                "CrashLoop".to_string(),
90                "0%".to_string(),
91                "32Mi".to_string(),
92                "2m".to_string(),
93            ],
94        ];
95
96        // Sort data based on current sort state
97        let mut rows = base_data.clone();
98        if let Some((col, ascending)) = sort_state.get() {
99            rows.sort_by(|a, b| {
100                let a_val = a.get(col).map(|s| s.as_str()).unwrap_or("");
101                let b_val = b.get(col).map(|s| s.as_str()).unwrap_or("");
102                if ascending {
103                    a_val.cmp(b_val)
104                } else {
105                    b_val.cmp(a_val)
106                }
107            });
108        }
109
110        let on_select = with!(selected => move |idx: usize| {
111            selected.set(idx);
112        });
113
114        let on_sort = with!(sort_state => move |col: usize, asc: bool| {
115            sort_state.set(Some((col, asc)));
116        });
117
118        let on_activate = with!(selected => move |idx: usize| {
119            // In a real app, this might open a details view
120            selected.set(idx);
121        });
122
123        let selected_name = rows
124            .get(selected.get())
125            .and_then(|r| r.first())
126            .map(|s| s.as_str())
127            .unwrap_or("None");
128
129        let sort_info = match sort_state.get() {
130            Some((col, asc)) => {
131                let col_name = match col {
132                    0 => "NAME",
133                    1 => "STATUS",
134                    2 => "CPU",
135                    3 => "MEMORY",
136                    4 => "AGE",
137                    _ => "?",
138                };
139                format!(
140                    "Sorted by {} ({})",
141                    col_name,
142                    if asc { "asc" } else { "desc" }
143                )
144            }
145            None => "Unsorted".to_string(),
146        };
147
148        View::vstack()
149            .child(
150                View::styled_text("Pod Dashboard")
151                    .color(Color::Cyan)
152                    .bold()
153                    .build(),
154            )
155            .child(
156                View::styled_text(format!("Selected: {} | {}", selected_name, sort_info))
157                    .dim()
158                    .build(),
159            )
160            .child(
161                View::boxed()
162                    .flex(1)
163                    .border(true)
164                    .child(
165                        View::table()
166                            .column("NAME")
167                            .column_with(TableColumn::new("STATUS").width(ColumnWidth::Fixed(12)))
168                            .column_with(
169                                TableColumn::new("CPU")
170                                    .width(ColumnWidth::Fixed(8))
171                                    .align(TextAlign::Right),
172                            )
173                            .column_with(
174                                TableColumn::new("MEMORY")
175                                    .width(ColumnWidth::Fixed(10))
176                                    .align(TextAlign::Right),
177                            )
178                            .column_with(
179                                TableColumn::new("AGE")
180                                    .width(ColumnWidth::Fixed(8))
181                                    .align(TextAlign::Right),
182                            )
183                            .rows(rows)
184                            .selected(selected.get())
185                            .sort(sort_state.get())
186                            .on_select(on_select)
187                            .on_sort(on_sort)
188                            .on_activate(on_activate)
189                            .build(),
190                    )
191                    .build(),
192            )
193            .child(
194                View::styled_text("↑↓/jk: navigate | Enter: activate | F1 help | Ctrl+Q: quit")
195                    .dim()
196                    .build(),
197            )
198            .child(
199                View::modal()
200                    .visible(show_help.get())
201                    .title("Example 17: Table")
202                    .on_dismiss(with!(show_help => move || show_help.set(false)))
203                    .child(
204                        View::vstack()
205                            .child(View::styled_text("What you're seeing").bold().build())
206                            .child(View::text("• Data table with sortable columns"))
207                            .child(View::text("• Row selection and activation"))
208                            .child(View::text("• Fixed and flexible column widths"))
209                            .child(View::gap(1))
210                            .child(View::styled_text("Key concepts").bold().build())
211                            .child(View::text("• View::table() for tabular data"))
212                            .child(View::text("• TableColumn for column config"))
213                            .child(View::text("• ColumnWidth::Fixed or ColumnWidth::Flex"))
214                            .child(View::text("• on_sort callback for sorting"))
215                            .child(View::gap(1))
216                            .child(View::styled_text("Try this").bold().build())
217                            .child(View::text("• Navigate rows with arrow keys"))
218                            .child(View::text("• Press Enter to activate a row"))
219                            .child(View::text("• Sorting is managed via on_sort"))
220                            .child(View::gap(1))
221                            .child(View::styled_text("Next up").bold().build())
222                            .child(View::text("→ 18_progress_bar: progress indicators"))
223                            .child(View::gap(1))
224                            .child(View::styled_text("Press Escape to close").dim().build())
225                            .build(),
226                    )
227                    .build(),
228            )
229            .build()
230    }

Trait Implementations§

Source§

impl Default for TableBuilder

Source§

fn default() -> TableBuilder

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.