node_launchpad/components/popup/
upgrade_nodes.rs

1// Copyright 2024 MaidSafe.net limited.
2//
3// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
4// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
5// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
6// KIND, either express or implied. Please review the Licences for the specific language governing
7// permissions and limitations relating to use of the SAFE Network Software.
8
9use super::super::utils::centered_rect_fixed;
10use super::super::Component;
11use crate::{
12    action::{Action, OptionsActions},
13    mode::{InputMode, Scene},
14    node_mgmt,
15    style::{clear_area, EUCALYPTUS, GHOST_WHITE, LIGHT_PERIWINKLE, VIVID_SKY_BLUE},
16};
17use color_eyre::Result;
18use crossterm::event::{KeyCode, KeyEvent};
19use ratatui::{prelude::*, widgets::*};
20
21pub struct UpgradeNodesPopUp {
22    /// Whether the component is active right now, capturing keystrokes + draw things.
23    active: bool,
24}
25
26impl UpgradeNodesPopUp {
27    pub fn new() -> Self {
28        Self { active: false }
29    }
30}
31
32impl Default for UpgradeNodesPopUp {
33    fn default() -> Self {
34        Self::new()
35    }
36}
37
38impl Component for UpgradeNodesPopUp {
39    fn handle_key_events(&mut self, key: KeyEvent) -> Result<Vec<Action>> {
40        if !self.active {
41            return Ok(vec![]);
42        }
43        // while in entry mode, keybinds are not captured, so gotta exit entry mode from here
44        let send_back = match key.code {
45            KeyCode::Enter => {
46                debug!("Got Enter, Upgrading nodes...");
47                vec![
48                    Action::OptionsActions(OptionsActions::UpdateNodes),
49                    Action::SwitchScene(Scene::Status),
50                ]
51            }
52            KeyCode::Esc => {
53                debug!("Got Esc, Not upgrading nodes.");
54                vec![Action::SwitchScene(Scene::Options)]
55            }
56            _ => vec![],
57        };
58        Ok(send_back)
59    }
60
61    fn update(&mut self, action: Action) -> Result<Option<Action>> {
62        let send_back = match action {
63            Action::SwitchScene(scene) => match scene {
64                Scene::UpgradeNodesPopUp => {
65                    self.active = true;
66                    Some(Action::SwitchInputMode(InputMode::Entry))
67                }
68                _ => {
69                    self.active = false;
70                    None
71                }
72            },
73            _ => None,
74        };
75        Ok(send_back)
76    }
77
78    fn draw(&mut self, f: &mut crate::tui::Frame<'_>, area: Rect) -> Result<()> {
79        if !self.active {
80            return Ok(());
81        }
82
83        let layer_zero = centered_rect_fixed(52, 15, area);
84
85        let layer_one = Layout::new(
86            Direction::Vertical,
87            [
88                // for the pop_up_border
89                Constraint::Length(2),
90                // for the input field
91                Constraint::Min(1),
92                // for the pop_up_border
93                Constraint::Length(1),
94            ],
95        )
96        .split(layer_zero);
97
98        // layer zero
99        let pop_up_border = Paragraph::new("").block(
100            Block::default()
101                .borders(Borders::ALL)
102                .title(" Upgrade all nodes ")
103                .bold()
104                .title_style(Style::new().fg(VIVID_SKY_BLUE))
105                .padding(Padding::uniform(2))
106                .border_style(Style::new().fg(VIVID_SKY_BLUE)),
107        );
108        clear_area(f, layer_zero);
109
110        // split the area into 3 parts, for the lines, hypertext,  buttons
111        let layer_two = Layout::new(
112            Direction::Vertical,
113            [
114                // for the text
115                Constraint::Length(10),
116                // gap
117                Constraint::Length(3),
118                // for the buttons
119                Constraint::Length(1),
120            ],
121        )
122        .split(layer_one[1]);
123
124        let text = Paragraph::new(vec![
125            Line::from(Span::styled("\n\n", Style::default())),
126            Line::from(vec![
127                Span::styled("This will ", Style::default().fg(LIGHT_PERIWINKLE)),
128                Span::styled(
129                    "stop and upgrade all nodes. ",
130                    Style::default().fg(GHOST_WHITE),
131                ),
132            ]),
133            Line::from(Span::styled(
134                "No data will be lost.",
135                Style::default().fg(LIGHT_PERIWINKLE),
136            )),
137            Line::from(Span::styled(
138                format!(
139                    "Upgrade time is {:.1?} seconds per node",
140                    node_mgmt::FIXED_INTERVAL / 1_000,
141                ),
142                Style::default().fg(LIGHT_PERIWINKLE),
143            )),
144            Line::from(Span::styled(
145                "plus, new binary download time.",
146                Style::default().fg(LIGHT_PERIWINKLE),
147            )),
148            Line::from(Span::styled("\n\n", Style::default())),
149            Line::from(vec![
150                Span::styled("You’ll need to ", Style::default().fg(LIGHT_PERIWINKLE)),
151                Span::styled("Start ", Style::default().fg(GHOST_WHITE)),
152                Span::styled(
153                    "them again afterwards.",
154                    Style::default().fg(LIGHT_PERIWINKLE),
155                ),
156            ]),
157            Line::from(Span::styled(
158                "Are you sure you want to continue?",
159                Style::default(),
160            )),
161        ])
162        .block(Block::default().padding(Padding::horizontal(2)))
163        .alignment(Alignment::Center)
164        .wrap(Wrap { trim: true });
165
166        f.render_widget(text, layer_two[0]);
167
168        let dash = Block::new()
169            .borders(Borders::BOTTOM)
170            .border_style(Style::new().fg(GHOST_WHITE));
171        f.render_widget(dash, layer_two[1]);
172
173        let buttons_layer =
174            Layout::horizontal(vec![Constraint::Percentage(45), Constraint::Percentage(55)])
175                .split(layer_two[2]);
176
177        let button_no = Line::from(vec![Span::styled(
178            "  No, Cancel [Esc]",
179            Style::default().fg(LIGHT_PERIWINKLE),
180        )]);
181        f.render_widget(button_no, buttons_layer[0]);
182
183        let button_yes = Paragraph::new(Line::from(vec![Span::styled(
184            "Yes, Upgrade [Enter]  ",
185            Style::default().fg(EUCALYPTUS),
186        )]))
187        .alignment(Alignment::Right);
188        f.render_widget(button_yes, buttons_layer[1]);
189        f.render_widget(pop_up_border, layer_zero);
190
191        Ok(())
192    }
193}