Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions openstack_tui/src/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ pub mod confirm_popup;
pub mod describe;
pub mod dns;
pub mod error_popup;
mod fuzzy_select_list;
pub mod header;
pub mod home;
pub mod identity;
Expand All @@ -42,7 +41,8 @@ pub mod project_select_popup;
pub mod resource_select_popup;
pub mod table_view;

pub use fuzzy_select_list::FuzzySelectList;
pub use crate::widgets::fuzzy_select::{FuzzySelect, FuzzySelectState};
pub use crate::widgets::popup::Popup;

/// `Component` is a trait that represents a visual and interactive element of the user interface.
/// Implementors of this trait can be registered with the main application loop and will be able to receive events,
Expand Down
51 changes: 18 additions & 33 deletions openstack_tui/src/components/cloud_select_popup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,21 @@

use crossterm::event::{KeyCode, KeyEvent};
use eyre::Result;
use ratatui::{prelude::*, widgets::*};
use ratatui::prelude::*;

use crate::{
action::Action,
components::{Component, FuzzySelectList},
components::{Component, FuzzySelect, FuzzySelectState},
config::Config,
error::TuiError,
mode::Mode,
utils::centered_rect_fixed,
};

const TITLE: &str = " Select cloud to connect: ";

pub struct CloudSelect {
config: Config,
fuzzy_list: FuzzySelectList,
popup_state: FuzzySelectState,
}

impl Default for CloudSelect {
Expand All @@ -42,56 +41,42 @@ impl CloudSelect {
pub fn new() -> Self {
Self {
config: Config::default(),
fuzzy_list: FuzzySelectList::new(),
popup_state: FuzzySelectState::new(),
}
}
}

impl Component for CloudSelect {
fn register_config_handler(&mut self, config: Config) -> Result<(), TuiError> {
self.config = config.clone();
self.fuzzy_list.register_config_handler(config.clone())?;
Ok(())
}

fn update(&mut self, action: Action, _current_mode: Mode) -> Result<Option<Action>, TuiError> {
if let Action::Clouds(ref clouds) = action {
self.fuzzy_list.set_items(clouds.clone());
};
if let Action::Clouds(clouds) = action {
let mut items: Vec<String> = clouds.to_vec();
items.sort_by_key(|a| a.to_lowercase());
self.popup_state.set_items(items);
}
Ok(None)
}

fn handle_key_events(&mut self, key: KeyEvent) -> Result<Option<Action>, TuiError> {
self.fuzzy_list.handle_key_events(key)?;
self.popup_state.handle_key(&key.code);
if key.code == KeyCode::Enter
&& let Some(cloud) = self.fuzzy_list.selected()
&& let Some(cloud) = self.popup_state.selected().cloned()
{
return Ok(Some(Action::ConnectToCloud(cloud.clone())));
return Ok(Some(Action::ConnectToCloud(cloud)));
}
Ok(None)
}

fn draw(&mut self, frame: &mut Frame<'_>, _area: Rect) -> Result<(), TuiError> {
let area = centered_rect_fixed(50, 35, frame.area());
let popup_block = Block::default()
.title_top(Line::from(TITLE.white()).centered())
.title_bottom(
Line::from(" (↑) move up | (↓) move down | (Enter) to connect ")
.gray()
.right_aligned(), //.alignment(Alignment::Right),
)
.borders(Borders::ALL)
.border_type(BorderType::Thick)
.bg(self.config.styles.popup_bg)
.padding(Padding::horizontal(1))
.border_style(Style::default().fg(self.config.styles.popup_border_fg));
let inner = popup_block.inner(area);

frame.render_widget(Clear, area);
frame.render_widget(popup_block, area);

self.fuzzy_list.draw(frame, inner)?;

fn draw(&mut self, frame: &mut Frame<'_>, area: Rect) -> Result<(), TuiError> {
frame.render_stateful_widget(
FuzzySelect::new(&self.config).as_popup(true).title(TITLE),
area,
&mut self.popup_state,
);
Ok(())
}
}
55 changes: 25 additions & 30 deletions openstack_tui/src/components/error_popup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ use ratatui::{layout::Rect, prelude::*, widgets::*};
use std::io::Write;

use crate::{
action::Action, components::Component, config::Config, error::TuiError, mode::Mode,
utils::centered_rect_fixed,
action::Action,
components::{Component, Popup},
config::Config,
error::TuiError,
mode::Mode,
};

const BOTTOM_TITLE: &str = "(Esc) to close";
Expand Down Expand Up @@ -137,7 +140,7 @@ impl Component for ErrorPopup {
self.source.clone_from(action);

self.text = strip_ansi_escapes::strip_str(msg)
.split("\n")
.split('\n')
.map(String::from)
.collect::<Vec<_>>();

Expand All @@ -147,7 +150,7 @@ impl Component for ErrorPopup {
"Please consider reporting the issue (press `r`).",
));
}
};
}
Ok(None)
}

Expand All @@ -163,32 +166,24 @@ impl Component for ErrorPopup {
Ok(None)
}

fn draw(&mut self, frame: &mut Frame<'_>, _area: Rect) -> Result<(), TuiError> {
let ar = centered_rect_fixed(120, 20, frame.area());
let popup_block = Block::default()
.title_top(Line::from(" Error ").red().centered())
.title_bottom(
Line::from(if self.source.is_some() {
BOTTOM_TITLE_WITH_REPORT
} else {
BOTTOM_TITLE
})
.gray()
.right_aligned(),
)
.borders(Borders::ALL)
.border_type(BorderType::Thick)
.padding(Padding::uniform(1))
.bg(self.config.styles.popup_bg)
.border_style(Style::default().fg(self.config.styles.popup_border_error_fg));
let text: Vec<Line> = self.text.clone().into_iter().map(Line::from).collect();
let paragraph = Paragraph::new(text)
.block(popup_block)
.scroll((self.scroll.1, self.scroll.0));

frame.render_widget(Clear, ar);
frame.render_widget(paragraph, ar);
fn draw(&mut self, frame: &mut Frame<'_>, area: Rect) -> Result<(), TuiError> {
// Build paragraph with scrolling
let lines: Vec<Line> = self.text.iter().map(|s| Line::from(s.clone())).collect();
let paragraph = Paragraph::new(lines).scroll((self.scroll.1, self.scroll.0));

// Title and optional bottom line
let title = Line::from(" Error ").red().centered();
let bottom = if self.source.is_some() {
Line::from(BOTTOM_TITLE_WITH_REPORT).gray().right_aligned()
} else {
Line::from(BOTTOM_TITLE).gray().right_aligned()
};

Ok(())
// Use generic Popup widget
let mut popup = Popup::new(self.config.clone(), title, paragraph)
.with_bottom_title(bottom)
.with_width_chars(120)
.with_border_color(self.config.styles.popup_border_error_fg);
popup.draw(frame, area)
}
}
Loading