quetty/components/
error_popup.rs

1use crate::components::base_popup::PopupBuilder;
2use crate::components::common::{Msg, PopupActivityMsg};
3use crate::components::state::ComponentState;
4use crate::error::AppError;
5use tuirealm::{
6    Component, Event, MockComponent, NoUserEvent,
7    command::{Cmd, CmdResult},
8    event::{Key, KeyEvent},
9    ratatui::{Frame, layout::Rect},
10};
11
12/// Error popup component that displays error messages to the user.
13///
14/// This component provides a consistent error display interface using the
15/// PopupBuilder pattern for standardized styling and behavior.
16///
17/// # Usage
18///
19/// ```rust
20/// use quetty::error::AppError;
21/// use quetty::components::error_popup::ErrorPopup;
22///
23/// let error = AppError::Config("Invalid configuration".to_string());
24/// let popup = ErrorPopup::new(&error);
25/// ```
26///
27/// # Events
28///
29/// - `KeyEvent::Enter` - Closes the error popup
30/// - `KeyEvent::Esc` - Closes the error popup
31///
32/// # Messages
33///
34/// Emits `Msg::PopupActivity(PopupActivityMsg::CloseError)` when closed.
35pub struct ErrorPopup {
36    message: String,
37    is_mounted: bool,
38}
39
40impl ErrorPopup {
41    /// Creates a new error popup with the specified error.
42    ///
43    /// # Arguments
44    ///
45    /// * `error` - The error to display, already formatted by ErrorReporter
46    ///
47    /// # Returns
48    ///
49    /// A new `ErrorPopup` instance ready for mounting.
50    pub fn new(error: &AppError) -> Self {
51        Self {
52            message: error.to_string(),
53            is_mounted: false,
54        }
55    }
56}
57
58impl MockComponent for ErrorPopup {
59    fn view(&mut self, frame: &mut Frame, area: Rect) {
60        PopupBuilder::error("❌ Error")
61            .add_multiline_text(&self.message)
62            .with_instructions("Press Enter or Esc to close")
63            .render(frame, area);
64    }
65
66    fn query(&self, _attr: tuirealm::Attribute) -> Option<tuirealm::AttrValue> {
67        None
68    }
69
70    fn attr(&mut self, _attr: tuirealm::Attribute, _value: tuirealm::AttrValue) {
71        // No attributes supported
72    }
73
74    fn state(&self) -> tuirealm::State {
75        tuirealm::State::None
76    }
77
78    fn perform(&mut self, _cmd: Cmd) -> CmdResult {
79        CmdResult::None
80    }
81}
82
83impl Component<Msg, NoUserEvent> for ErrorPopup {
84    fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> {
85        match ev {
86            Event::Keyboard(KeyEvent {
87                code: Key::Enter | Key::Esc,
88                ..
89            }) => Some(Msg::PopupActivity(PopupActivityMsg::CloseError)),
90            _ => None,
91        }
92    }
93}
94
95impl ComponentState for ErrorPopup {
96    fn mount(&mut self) -> crate::error::AppResult<()> {
97        log::debug!("Mounting ErrorPopup component");
98
99        if self.is_mounted {
100            log::warn!("ErrorPopup is already mounted");
101            return Ok(());
102        }
103
104        self.is_mounted = true;
105        log::debug!("ErrorPopup component mounted successfully");
106        Ok(())
107    }
108}
109
110impl Drop for ErrorPopup {
111    fn drop(&mut self) {
112        log::debug!("Dropping ErrorPopup component");
113        self.is_mounted = false;
114        log::debug!("ErrorPopup component dropped");
115    }
116}