pub struct TableBuilder { /* private fields */ }Expand description
Builder for Table views.
Implementations§
Source§impl TableBuilder
impl TableBuilder
pub fn new() -> Self
Sourcepub fn column(self, header: impl Into<String>) -> Self
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 }Sourcepub fn column_with(self, column: TableColumn) -> Self
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 }Sourcepub fn rows(self, rows: Vec<Vec<String>>) -> Self
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 }Sourcepub fn selected(self, index: usize) -> Self
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 }Sourcepub fn sort(self, sort: Option<(usize, bool)>) -> Self
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 }Sourcepub fn sort_by(self, column: usize, ascending: bool) -> Self
pub fn sort_by(self, column: usize, ascending: bool) -> Self
Set the sort state with explicit column and direction.
Sourcepub fn on_select(self, callback: impl Fn(usize) + 'static) -> Self
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 }Sourcepub fn on_sort(self, callback: impl Fn(usize, bool) + 'static) -> Self
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 }Sourcepub fn on_activate(self, callback: impl Fn(usize) + 'static) -> Self
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 }Sourcepub fn build(self) -> View
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
impl Default for TableBuilder
Source§fn default() -> TableBuilder
fn default() -> TableBuilder
Returns the “default value” for a type. Read more
Auto Trait Implementations§
impl Freeze for TableBuilder
impl !RefUnwindSafe for TableBuilder
impl !Send for TableBuilder
impl !Sync for TableBuilder
impl Unpin for TableBuilder
impl !UnwindSafe for TableBuilder
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
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>
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)
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)
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.