From 04b4220c76c45775887cee841ad61817d21988b5 Mon Sep 17 00:00:00 2001 From: filipriec Date: Sat, 22 Mar 2025 19:37:41 +0100 Subject: [PATCH] needs bug fixing --- client/src/components/admin/admin_panel.rs | 106 +++++++++++++++++---- client/src/components/handlers/sidebar.rs | 64 +++++++------ client/src/state/state.rs | 1 + 3 files changed, 128 insertions(+), 43 deletions(-) diff --git a/client/src/components/admin/admin_panel.rs b/client/src/components/admin/admin_panel.rs index eb4becc..150d726 100644 --- a/client/src/components/admin/admin_panel.rs +++ b/client/src/components/admin/admin_panel.rs @@ -1,21 +1,49 @@ // src/components/admin/admin_panel.rs + use ratatui::{ - layout::{Alignment, Constraint, Direction, Layout, Rect}, + widgets::{Block, BorderType, Borders, List, ListItem, ListState, Paragraph}, style::Style, - text::{Line, Span}, - widgets::{Block, BorderType, Borders, Paragraph}, + text::{Line, Span, Text}, + layout::{Alignment, Constraint, Direction, Layout, Rect}, Frame, }; +use common::proto::multieko2::table_definition::ProfileTreeResponse; use crate::config::colors::Theme; -pub struct AdminPanelState; +pub struct AdminPanelState { + pub list_state: ListState, + pub profiles: Vec, +} impl AdminPanelState { - pub fn new() -> Self { - Self + pub fn new(profiles: Vec) -> Self { + let mut list_state = ListState::default(); + if !profiles.is_empty() { + list_state.select(Some(0)); + } + Self { list_state, profiles } } - pub fn render(&self, f: &mut Frame, area: Rect, theme: &Theme) { + pub fn next(&mut self) { + let i = self.list_state.selected().map_or(0, |i| + if i >= self.profiles.len() - 1 { 0 } else { i + 1 }); + self.list_state.select(Some(i)); + } + + pub fn previous(&mut self) { + let i = self.list_state.selected().map_or(0, |i| + if i == 0 { self.profiles.len() - 1 } else { i - 1 }); + self.list_state.select(Some(i)); + } + + pub fn render( + &mut self, + f: &mut Frame, + area: Rect, + theme: &Theme, + profile_tree: &ProfileTreeResponse, + selected_profile: &Option, + ) { let block = Block::default() .borders(Borders::ALL) .border_type(BorderType::Rounded) @@ -27,18 +55,64 @@ impl AdminPanelState { let chunks = Layout::default() .direction(Direction::Vertical) - .constraints([ - Constraint::Length(3), // Title - Constraint::Min(1), // Content - ]) + .constraints([Constraint::Length(3), Constraint::Min(1)]) .split(inner_area); + // Title let title = Line::from(Span::styled("Admin Panel", Style::default().fg(theme.highlight))); - let title_para = Paragraph::new(title) - .alignment(Alignment::Center); - f.render_widget(title_para, chunks[0]); + Paragraph::new(title) + .alignment(Alignment::Center) + .render(f, chunks[0]); - let content = Paragraph::new("Admin panel content goes here"); - f.render_widget(content, chunks[1]); + // Content + let content_chunks = Layout::default() + .direction(Direction::Horizontal) + .constraints([Constraint::Percentage(30), Constraint::Percentage(70)]) + .split(chunks[1]); + + // Profile list + let items: Vec = self.profiles.iter() + .map(|p| ListItem::new(Line::from(vec![ + Span::styled( + if Some(p) == selected_profile { "✓ " } else { " " }, + Style::default().fg(theme.accent) + ), + Span::styled(p, Style::default().fg(theme.fg)), + ]))) + .collect(); + + List::new(items) + .block(Block::default().title("Profiles")) + .highlight_style(Style::default().bg(theme.highlight).fg(theme.bg)) + .render_stateful(f, content_chunks[0], &mut self.list_state); + + // Profile details + if let Some(profile) = self.list_state.selected() + .and_then(|i| profile_tree.profiles.get(i)) + { + let mut text = Text::default(); + text.lines.push(Line::from(vec![ + Span::styled("Profile: ", Style::default().fg(theme.accent)), + Span::styled(&profile.name, Style::default().fg(theme.highlight)), + ])); + + text.lines.push(Line::from("")); + text.lines.push(Line::from(Span::styled("Tables:", Style::default().fg(theme.accent)))); + + for table in &profile.tables { + let mut line = vec![Span::styled(format!("├─ {}", table.name), theme.fg)]; + if !table.depends_on.is_empty() { + line.push(Span::styled( + format!(" → {}", table.depends_on.join(", ")), + Style::default().fg(theme.secondary) + )); + } + text.lines.push(Line::from(line)); + } + + Paragraph::new(text) + .block(Block::default().title("Details")) + .render(f, content_chunks[1]); + } } } diff --git a/client/src/components/handlers/sidebar.rs b/client/src/components/handlers/sidebar.rs index 81ef43d..bb4d266 100644 --- a/client/src/components/handlers/sidebar.rs +++ b/client/src/components/handlers/sidebar.rs @@ -26,41 +26,51 @@ pub fn calculate_sidebar_layout(show_sidebar: bool, main_content_area: Rect) -> } } -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)); - +pub fn render_sidebar( + f: &mut Frame, + area: Rect, + theme: &Theme, + profile_tree: &ProfileTreeResponse, + selected_profile: &Option, +) { + let sidebar_block = Block::default().style(Style::default().bg(theme.bg)); 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 + if let Some(profile_name) = selected_profile { + if let Some(profile) = profile_tree.profiles.iter() + .find(|p| &p.name == profile_name) + { + // Profile header 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)), + Span::styled("📁 ", Style::default().fg(theme.accent)), + Span::styled(&profile.name, Style::default().fg(theme.highlight)), ]))); - // Dependencies - if !table.depends_on.is_empty() { - let dep_prefix = if is_last_table { " " } else { "│ " }; - let deps = table.depends_on.join(", "); + // Tables + for (table_idx, table) in profile.tables.iter().enumerate() { + let is_last = table_idx == profile.tables.len() - 1; + let prefix = if is_last { "└─ " } else { "├─ " }; - 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 mut line = vec![ + Span::styled(format!(" {}", prefix), Style::default().fg(theme.fg)), + Span::styled(&table.name, Style::default().fg(theme.fg)), + ]; + + if !table.depends_on.is_empty() { + line.push(Span::styled( + format!(" → {}", table.depends_on.join(", ")), + Style::default().fg(theme.secondary) + )); + } + + items.push(ListItem::new(Line::from(line))); } } + } else { + items.push(ListItem::new(Span::styled( + "No profile selected", + Style::default().fg(theme.secondary) + ))); } let list = List::new(items) diff --git a/client/src/state/state.rs b/client/src/state/state.rs index 54ec286..8311e94 100644 --- a/client/src/state/state.rs +++ b/client/src/state/state.rs @@ -16,6 +16,7 @@ pub struct AppState { pub total_count: u64, pub current_position: u64, pub profile_tree: ProfileTreeResponse, + pub selected_profile: Option, // UI preferences pub ui: UiState,