diff --git a/client/src/components/handlers/sidebar.rs b/client/src/components/handlers/sidebar.rs index cf509d0..a836965 100644 --- a/client/src/components/handlers/sidebar.rs +++ b/client/src/components/handlers/sidebar.rs @@ -7,6 +7,8 @@ use ratatui::{ Frame, }; use crate::config::colors::Theme; +use common::proto::multieko2::table_definition::{ProfileTreeResponse, profile_tree_response::Profile}; +use ratatui::text::{Span, Line}; const SIDEBAR_WIDTH: u16 = 16; @@ -25,15 +27,42 @@ pub fn calculate_sidebar_layout(show_sidebar: bool, main_content_area: Rect) -> } } -pub fn render_sidebar(f: &mut Frame, area: Rect, theme: &Theme) { +pub fn render_sidebar(f: &mut Frame, area: Rect, theme: &Theme, profile_tree: &ProfileTreeResponse) { let sidebar_block = Block::default() .style(Style::default().bg(theme.bg)); - let items = vec![ - ListItem::new(Text::from(" Navigation ")), - ListItem::new(Text::from(" Search ")), - ListItem::new(Text::from(" Settings ")), - ]; + let mut items = Vec::new(); + + for profile in &profile_tree.profiles { + // Profile header + items.push(ListItem::new(Line::from(vec![ + Span::styled("📁 ", Style::default().fg(theme.accent)), + Span::styled(&profile.name, Style::default().fg(theme.highlight)), + ]))); + + // Profile tables + for (table_idx, table) in profile.tables.iter().enumerate() { + let is_last_table = table_idx == profile.tables.len() - 1; + let tree_prefix = if is_last_table { "└─ " } else { "├─ " }; + + // Table name + items.push(ListItem::new(Line::from(vec![ + Span::styled(format!(" {}", tree_prefix), Style::default().fg(theme.fg)), + Span::styled(&table.name, Style::default().fg(theme.fg)), + ]))); + + // Dependencies + if !table.depends_on.is_empty() { + let dep_prefix = if is_last_table { " " } else { "│ " }; + let deps = table.depends_on.join(", "); + + items.push(ListItem::new(Line::from(vec![ + Span::styled(format!(" {} └─ ", dep_prefix), Style::default().fg(theme.secondary)), + Span::styled(format!("→ {}", deps), Style::default().fg(theme.secondary)), + ]))); + } + } + } let list = List::new(items) .block(sidebar_block) diff --git a/client/src/state/state.rs b/client/src/state/state.rs index 8ef3012..09a86e8 100644 --- a/client/src/state/state.rs +++ b/client/src/state/state.rs @@ -1,11 +1,11 @@ // src/client/ui/handlers/state.rs use std::env; +use common::proto::multieko2::table_definition::ProfileTreeResponse; -#[derive(Default)] pub struct UiState { pub show_sidebar: bool, - // Add other UI-related states here + pub profile_tree: ProfileTreeResponse, } pub struct AppState { @@ -42,3 +42,12 @@ impl AppState { self.current_position = current_position; } } + +impl Default for UiState { + fn default() -> Self { + Self { + show_sidebar: true, + profile_tree: ProfileTreeResponse::default(), + } + } +} diff --git a/client/src/tui/terminal/grpc_client.rs b/client/src/tui/terminal/grpc_client.rs index 8862c00..2659fb8 100644 --- a/client/src/tui/terminal/grpc_client.rs +++ b/client/src/tui/terminal/grpc_client.rs @@ -6,17 +6,28 @@ use common::proto::multieko2::adresar::{AdresarResponse, PostAdresarRequest, Put use common::proto::multieko2::common::{CountResponse, PositionRequest, Empty}; use common::proto::multieko2::table_structure::table_structure_service_client::TableStructureServiceClient; use common::proto::multieko2::table_structure::TableStructureResponse; +use common::proto::multieko2::table_definition::{ + table_definition_client::TableDefinitionClient, + ProfileTreeResponse +}; pub struct GrpcClient { adresar_client: AdresarClient, table_structure_client: TableStructureServiceClient, + table_definition_client: TableDefinitionClient, } impl GrpcClient { pub async fn new() -> Result> { let adresar_client = AdresarClient::connect("http://[::1]:50051").await?; let table_structure_client = TableStructureServiceClient::connect("http://[::1]:50051").await?; - Ok(Self { adresar_client, table_structure_client }) + let table_definition_client = TableDefinitionClient::connect("http://[::1]:50051").await?; + + Ok(Self { + adresar_client, + table_structure_client, + table_definition_client, + }) } pub async fn get_adresar_count(&mut self) -> Result> { @@ -48,4 +59,10 @@ impl GrpcClient { let response = self.table_structure_client.get_adresar_table_structure(request).await?; Ok(response.into_inner()) } + + pub async fn get_profile_tree(&mut self) -> Result> { + let request = tonic::Request::new(Empty::default()); + let response = self.table_definition_client.get_profile_tree(request).await?; + Ok(response.into_inner()) + } } diff --git a/client/src/ui/handlers/render.rs b/client/src/ui/handlers/render.rs index df937c3..0611fea 100644 --- a/client/src/ui/handlers/render.rs +++ b/client/src/ui/handlers/render.rs @@ -69,7 +69,7 @@ pub fn render_ui( ); if let Some(sidebar_rect) = sidebar_area { - sidebar::render_sidebar(f, sidebar_rect, theme); + sidebar::render_sidebar(f, sidebar_rect, theme, &ui_state.profile_tree); } render_status_line(f, root[1], current_dir, theme, is_edit_mode); diff --git a/client/src/ui/handlers/ui.rs b/client/src/ui/handlers/ui.rs index 2780885..6381cd1 100644 --- a/client/src/ui/handlers/ui.rs +++ b/client/src/ui/handlers/ui.rs @@ -32,10 +32,15 @@ pub async fn run_ui() -> Result<(), Box> { // Initialize FormState with dynamic fields let mut form_state = FormState::new(column_names); + // Fetch profile tree and table structure + let profile_tree = grpc_client.get_profile_tree().await?; + let table_structure = grpc_client.get_table_structure().await?; + // The rest of your UI initialization remains the same let mut event_handler = EventHandler::new(); let event_reader = EventReader::new(); let mut app_state = AppState::new()?; + app_state.ui.profile_tree = profile_tree; // Fetch the total count of Adresar entries let total_count = grpc_client.get_adresar_count().await?;