quetty 0.1.9

Terminal-based Azure Service Bus queue manager with intuitive TUI interface
Documentation
use crate::components::base_popup::PopupBuilder;
use crate::components::common::{Msg, ResourceGroupSelectionMsg};
use crate::theme::ThemeManager;
use quetty_server::service_bus_manager::azure_management_client::ResourceGroup;
use tuirealm::command::{Cmd, CmdResult};
use tuirealm::event::{Event, Key, KeyEvent, NoUserEvent};
use tuirealm::props::TextModifiers;
use tuirealm::ratatui::layout::Rect;
use tuirealm::ratatui::style::Style;
use tuirealm::ratatui::widgets::{List, ListItem};
use tuirealm::{AttrValue, Attribute, Component, Frame, MockComponent, State, StateValue};

pub struct ResourceGroupPicker {
    resource_groups: Vec<ResourceGroup>,
    selected: usize,
}

impl ResourceGroupPicker {
    pub fn new(resource_groups: Option<Vec<ResourceGroup>>) -> Self {
        Self {
            resource_groups: resource_groups.unwrap_or_default(),
            selected: 0,
        }
    }
}

impl MockComponent for ResourceGroupPicker {
    fn view(&mut self, frame: &mut Frame, area: Rect) {
        let items: Vec<ListItem> = if self.resource_groups.is_empty() {
            vec![
                ListItem::new("⚠️  No resource groups found")
                    .style(Style::default().fg(ThemeManager::text_muted())),
                ListItem::new(""),
                ListItem::new("This may be due to limited permissions.")
                    .style(Style::default().fg(ThemeManager::text_muted())),
                ListItem::new("Press ESC to go back to subscription selection.")
                    .style(Style::default().fg(ThemeManager::text_muted())),
            ]
        } else {
            self.resource_groups
                .iter()
                .enumerate()
                .map(|(i, group)| {
                    let group_text = format!("📁 {} ({})", group.name, group.location);
                    let mut item = ListItem::new(group_text);
                    if i == self.selected {
                        item = item.style(
                            Style::default()
                                .fg(ThemeManager::primary_accent())
                                .bg(ThemeManager::surface())
                                .add_modifier(TextModifiers::BOLD),
                        );
                    } else {
                        item = item.style(Style::default().fg(ThemeManager::text_primary()));
                    }
                    item
                })
                .collect()
        };

        let popup_block = PopupBuilder::new("Resource Group Picker")
            .create_block_with_title("  📁 Select Resource Group  ");

        let list = List::new(items)
            .block(popup_block)
            .highlight_style(
                Style::default()
                    .fg(ThemeManager::primary_accent())
                    .bg(ThemeManager::surface())
                    .add_modifier(TextModifiers::BOLD),
            )
            .highlight_symbol("");
        frame.render_widget(list, area);
    }

    fn query(&self, _attr: Attribute) -> Option<AttrValue> {
        None
    }

    fn attr(&mut self, _attr: Attribute, _value: AttrValue) {}

    fn state(&self) -> State {
        if let Some(group) = self.resource_groups.get(self.selected) {
            State::One(StateValue::String(group.name.clone()))
        } else {
            State::None
        }
    }

    fn perform(&mut self, _cmd: Cmd) -> CmdResult {
        CmdResult::None
    }
}

impl Component<Msg, NoUserEvent> for ResourceGroupPicker {
    fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> {
        match ev {
            Event::Keyboard(KeyEvent { code: Key::Esc, .. }) => Some(Msg::ResourceGroupSelection(
                ResourceGroupSelectionMsg::CancelSelection,
            )),
            Event::Keyboard(KeyEvent {
                code: Key::Enter, ..
            }) => self.resource_groups.get(self.selected).map(|group| {
                Msg::ResourceGroupSelection(ResourceGroupSelectionMsg::ResourceGroupSelected(
                    group.name.clone(),
                ))
            }),
            Event::Keyboard(KeyEvent {
                code: Key::Up | Key::Char('k'),
                ..
            }) => {
                if self.selected > 0 {
                    self.selected -= 1;
                    Some(Msg::ResourceGroupSelection(
                        ResourceGroupSelectionMsg::SelectionChanged,
                    ))
                } else {
                    None
                }
            }
            Event::Keyboard(KeyEvent {
                code: Key::Down | Key::Char('j'),
                ..
            }) => {
                if self.selected < self.resource_groups.len().saturating_sub(1) {
                    self.selected += 1;
                    Some(Msg::ResourceGroupSelection(
                        ResourceGroupSelectionMsg::SelectionChanged,
                    ))
                } else {
                    None
                }
            }
            _ => None,
        }
    }
}