11use crate :: {
2- interpreter:: { ContextArc , options:: ChDigViews } ,
3- view:: { self , Navigation , ViewProvider } ,
2+ actions:: ActionDescription ,
3+ common:: RelativeDateTime ,
4+ interpreter:: { ContextArc , TextLogArguments , options:: ChDigViews } ,
5+ utils:: fuzzy_actions,
6+ view:: { self , Navigation , TextLogView , ViewProvider } ,
47} ;
58use cursive:: {
69 Cursive ,
10+ event:: Event ,
711 view:: { Nameable , Resizable } ,
8- views:: { Dialog , DummyView , LinearLayout , TextView } ,
12+ views:: { Dialog , DummyView , LinearLayout , NamedView , TextView } ,
913} ;
1014use std:: collections:: HashMap ;
1115
@@ -30,11 +34,12 @@ fn build_query(
3034 filters : & super :: TableFilterParams ,
3135 is_dialog : bool ,
3236) -> String {
33- let ( limit, dbtable , clickhouse, selected_host) = {
37+ let ( limit, parts_dbtable , tables_dbtable , clickhouse, selected_host) = {
3438 let ctx = context. lock ( ) . unwrap ( ) ;
3539 (
3640 ctx. options . clickhouse . limit ,
3741 ctx. clickhouse . get_table_name ( "system" , "parts" ) ,
42+ ctx. clickhouse . get_table_name ( "system" , "tables" ) ,
3843 ctx. clickhouse . clone ( ) ,
3944 ctx. selected_host . clone ( ) ,
4045 )
@@ -50,42 +55,48 @@ fn build_query(
5055 let where_clause = if where_clauses. is_empty ( ) {
5156 String :: new ( )
5257 } else {
53- format ! ( "WHERE {}" , where_clauses. join( " AND " ) )
58+ format ! ( " WHERE {}" , where_clauses. join( " AND " ) )
5459 } ;
5560
5661 let select_clause = if is_dialog {
57- r#"name,
58- partition,
59- rows,
60- bytes_on_disk,
61- data_compressed_bytes,
62- data_uncompressed_bytes,
63- modification_time,
64- active"#
62+ r#"parts.name,
63+ parts.partition,
64+ parts.rows,
65+ parts.bytes_on_disk,
66+ parts.data_compressed_bytes,
67+ parts.data_uncompressed_bytes,
68+ parts.modification_time,
69+ parts.active,
70+ tables.uuid::String _table_uuid"#
6571 } else {
66- r#"database,
67- table,
68- name,
69- partition,
70- rows,
71- bytes_on_disk,
72- data_compressed_bytes,
73- data_uncompressed_bytes,
74- modification_time,
75- active"#
72+ r#"parts.database,
73+ parts.table,
74+ parts.name,
75+ parts.partition,
76+ parts.rows,
77+ parts.bytes_on_disk,
78+ parts.data_compressed_bytes,
79+ parts.data_uncompressed_bytes,
80+ parts.modification_time,
81+ parts.active,
82+ tables.uuid::String _table_uuid"#
7683 } ;
7784
7885 format ! (
7986 r#"
8087 SELECT
8188 {select_clause}
82- FROM {dbtable}
89+ FROM {parts_dbtable} as parts
90+ LEFT JOIN (SELECT DISTINCT ON (database, name) database, name, uuid FROM {tables_dbtable}) tables
91+ ON parts.database = tables.database AND parts.table = tables.name
8392 {where_clause}
84- ORDER BY modification_time DESC
93+ ORDER BY parts. modification_time DESC
8594 LIMIT {limit}
95+ SETTINGS allow_experimental_analyzer=1
8696 "# ,
8797 select_clause = select_clause,
88- dbtable = dbtable,
98+ parts_dbtable = parts_dbtable,
99+ tables_dbtable = tables_dbtable,
89100 where_clause = where_clause,
90101 limit = limit,
91102 )
@@ -102,6 +113,7 @@ fn get_columns(is_dialog: bool) -> (Vec<&'static str>, Vec<&'static str>) {
102113 "data_uncompressed_bytes" ,
103114 "modification_time" ,
104115 "active" ,
116+ "_table_uuid" ,
105117 ]
106118 } else {
107119 vec ! [
@@ -115,12 +127,48 @@ fn get_columns(is_dialog: bool) -> (Vec<&'static str>, Vec<&'static str>) {
115127 "data_uncompressed_bytes" ,
116128 "modification_time" ,
117129 "active" ,
130+ "_table_uuid" ,
118131 ]
119132 } ;
120133 let columns_to_compare = vec ! [ "name" ] ;
121134 ( columns, columns_to_compare)
122135}
123136
137+ fn show_part_logs ( siv : & mut Cursive , columns : Vec < & ' static str > , row : view:: QueryResultRow ) {
138+ let mut map = HashMap :: new ( ) ;
139+ columns. iter ( ) . zip ( row. 0 . iter ( ) ) . for_each ( |( c, r) | {
140+ map. insert ( c. to_string ( ) , r) ;
141+ } ) ;
142+
143+ let context = siv. user_data :: < ContextArc > ( ) . unwrap ( ) . clone ( ) ;
144+ siv. add_layer ( Dialog :: around (
145+ LinearLayout :: vertical ( )
146+ . child ( TextView :: new ( "Logs:" ) . center ( ) )
147+ . child ( DummyView . fixed_height ( 1 ) )
148+ . child ( NamedView :: new (
149+ "part_logs" ,
150+ TextLogView :: new (
151+ "part_logs" ,
152+ context,
153+ TextLogArguments {
154+ query_ids : Some ( vec ! [ format!(
155+ "{}::{}" ,
156+ map[ "_table_uuid" ] . to_string( ) ,
157+ map[ "name" ] . to_string( )
158+ ) ] ) ,
159+ logger_names : None ,
160+ hostname : None ,
161+ message_filter : None ,
162+ max_level : None ,
163+ start : map[ "modification_time" ] . as_datetime ( ) . unwrap ( ) ,
164+ end : RelativeDateTime :: new ( None ) ,
165+ } ,
166+ ) ,
167+ ) ) ,
168+ ) ) ;
169+ siv. focus_name ( "part_logs" ) . unwrap ( ) ;
170+ }
171+
124172fn show_part_details ( siv : & mut Cursive , columns : Vec < & ' static str > , row : view:: QueryResultRow ) {
125173 let row_data = row. 0 ;
126174 let mut map = HashMap :: < String , String > :: new ( ) ;
@@ -140,6 +188,36 @@ fn show_part_details(siv: &mut Cursive, columns: Vec<&'static str>, row: view::Q
140188 siv. add_layer ( Dialog :: info ( info) . title ( "Part Details" ) ) ;
141189}
142190
191+ fn table_parts_action_callback (
192+ siv : & mut Cursive ,
193+ columns : Vec < & ' static str > ,
194+ row : view:: QueryResultRow ,
195+ ) {
196+ let actions = vec ! [
197+ ActionDescription {
198+ text: "Show part logs" ,
199+ event: Event :: Unknown ( vec![ ] ) ,
200+ } ,
201+ ActionDescription {
202+ text: "Show part details" ,
203+ event: Event :: Unknown ( vec![ ] ) ,
204+ } ,
205+ ] ;
206+
207+ let columns_clone = columns. clone ( ) ;
208+ let row_clone = row. clone ( ) ;
209+
210+ fuzzy_actions ( siv, actions, move |siv, selected| match selected. as_str ( ) {
211+ "Show part logs" => {
212+ show_part_logs ( siv, columns_clone. clone ( ) , row_clone. clone ( ) ) ;
213+ }
214+ "Show part details" => {
215+ show_part_details ( siv, columns_clone. clone ( ) , row_clone. clone ( ) ) ;
216+ }
217+ _ => { }
218+ } ) ;
219+ }
220+
143221pub fn show_table_parts (
144222 siv : & mut Cursive ,
145223 context : ContextArc ,
@@ -167,7 +245,8 @@ pub fn show_table_parts(
167245 )
168246 . unwrap_or_else ( |_| panic ! ( "Cannot create {}" , view_name) ) ;
169247
170- view. get_inner_mut ( ) . set_on_submit ( show_part_details) ;
248+ view. get_inner_mut ( )
249+ . set_on_submit ( table_parts_action_callback) ;
171250
172251 let title = filters. build_title ( false ) ;
173252
@@ -202,7 +281,9 @@ pub fn show_table_parts_dialog(
202281 )
203282 . unwrap_or_else ( |_| panic ! ( "Cannot create {}" , view_name) ) ;
204283
205- sql_view. get_inner_mut ( ) . set_on_submit ( show_part_details) ;
284+ sql_view
285+ . get_inner_mut ( )
286+ . set_on_submit ( table_parts_action_callback) ;
206287
207288 let title = filters. build_title ( true ) ;
208289
0 commit comments