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
1 change: 1 addition & 0 deletions coman/src/app/ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ pub enum Id {
InfoPopup,
ErrorPopup,
LoginPopup,
SystemSelectPopup,
}
12 changes: 12 additions & 0 deletions coman/src/app/messages.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::cscs::api_client::System;

#[derive(Debug, PartialEq)]
pub enum MenuMsg {
Opened,
Closed,
CscsLogin,
CscsSwitchSystem,
}

#[derive(Debug, PartialEq)]
Expand All @@ -22,10 +25,18 @@ pub enum LoginPopupMsg {
Closed,
LoginDone(String, String),
}
#[derive(Debug, PartialEq)]
pub enum SystemSelectMsg {
Opened(Vec<System>),
Closed,
SystemSelected(String),
}

#[derive(Debug, PartialEq)]
pub enum CscsMsg {
Login(String, String),
SelectSystem,
SystemSelected(String),
}

#[derive(Debug, PartialEq)]
Expand All @@ -35,6 +46,7 @@ pub enum Msg {
InfoPopup(InfoPopupMsg),
ErrorPopup(ErrorPopupMsg),
LoginPopup(LoginPopupMsg),
SystemSelectPopup(SystemSelectMsg),
Error(String),
Info(String),
Cscs(CscsMsg),
Expand Down
73 changes: 69 additions & 4 deletions coman/src/app/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ use tuirealm::{
use crate::{
app::{
ids::Id,
messages::{CscsMsg, ErrorPopupMsg, InfoPopupMsg, LoginPopupMsg, MenuMsg, Msg},
messages::{
CscsMsg, ErrorPopupMsg, InfoPopupMsg, LoginPopupMsg, MenuMsg, Msg, SystemSelectMsg,
},
user_events::UserEvent,
},
components::{
error_popup::ErrorPopup, info_popup::InfoPopup, login_popup::LoginPopup,
workload_menu::WorkloadMenu,
system_select_popup::SystemSelectPopup, workload_menu::WorkloadMenu,
},
cscs::cli::cscs_login,
cscs::{cli::cscs_login, handlers::cscs_system_set},
trace_dbg,
util::ui::draw_area_in_absolute,
};
Expand All @@ -37,6 +39,9 @@ where

///Used to allow sending errors from tokio::spawn async jobs
pub error_tx: mpsc::Sender<String>,

/// Triggers async request to select current system
pub select_system_tx: mpsc::Sender<()>,
}

impl<T> Model<T>
Expand All @@ -47,13 +52,15 @@ where
app: Application<Id, Msg, UserEvent>,
bridge: TerminalBridge<T>,
error_tx: mpsc::Sender<String>,
select_system_tx: mpsc::Sender<()>,
) -> Self {
Self {
app,
quit: false,
redraw: true,
terminal: bridge,
error_tx,
select_system_tx,
}
}

Expand Down Expand Up @@ -91,6 +98,10 @@ where
let popup = draw_area_in_absolute(f.area(), 10);
f.render_widget(Clear, popup);
self.app.view(&Id::LoginPopup, f, popup);
} else if self.app.mounted(&Id::SystemSelectPopup) {
let popup = draw_area_in_absolute(f.area(), 10);
f.render_widget(Clear, popup);
self.app.view(&Id::SystemSelectPopup, f, popup);
}
})
.is_ok()
Expand All @@ -117,6 +128,32 @@ where
}
}
}
fn handle_system_select_popup_msg(&mut self, msg: SystemSelectMsg) -> Option<Msg> {
match msg {
SystemSelectMsg::Opened(systems) => {
assert!(
self.app
.mount(
Id::SystemSelectPopup,
Box::new(SystemSelectPopup::new(systems)),
vec![]
)
.is_ok()
);
assert!(self.app.active(&Id::SystemSelectPopup).is_ok());
trace_dbg!("mounted system select popup");
None
}
SystemSelectMsg::Closed => {
assert!(self.app.umount(&Id::SystemSelectPopup).is_ok());
None
}
SystemSelectMsg::SystemSelected(system) => {
assert!(self.app.umount(&Id::SystemSelectPopup).is_ok());
Some(Msg::Cscs(CscsMsg::SystemSelected(system)))
}
}
}
fn handle_error_popup_msg(&mut self, msg: ErrorPopupMsg) -> Option<Msg> {
match msg {
ErrorPopupMsg::Opened(error_msg) => {
Expand Down Expand Up @@ -174,6 +211,10 @@ where
assert!(self.app.umount(&Id::Menu).is_ok());
Some(Msg::LoginPopup(LoginPopupMsg::Opened))
}
MenuMsg::CscsSwitchSystem => {
assert!(self.app.umount(&Id::Menu).is_ok());
Some(Msg::Cscs(CscsMsg::SelectSystem))
}
}
}
}
Expand Down Expand Up @@ -218,8 +259,32 @@ where
});
None
}
Msg::None => None,
Msg::Cscs(CscsMsg::SelectSystem) => {
let system_select_tx = self.select_system_tx.clone();
tokio::spawn(async move {
system_select_tx.send(()).await.unwrap();
});
None
}
Msg::Cscs(CscsMsg::SystemSelected(system)) => {
let error_tx = self.error_tx.clone();
tokio::spawn(async move {
match cscs_system_set(system, true).await {
Ok(_) => {}
Err(e) => error_tx
.send(format!(
"{:?}",
Err::<(), Report>(e).wrap_err("failed to set current system")
))
.await
.unwrap(),
};
});
None
}
Msg::LoginPopup(msg) => self.handle_login_popup_msg(msg),
Msg::SystemSelectPopup(msg) => self.handle_system_select_popup_msg(msg),
Msg::None => None,
}
} else {
None
Expand Down
3 changes: 2 additions & 1 deletion coman/src/app/user_events.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::cscs::api_client::Job;
use crate::cscs::api_client::{Job, System};

#[derive(Debug, Eq, Clone, PartialEq, PartialOrd, Ord)]
pub enum CscsEvent {
LoggedIn,
GotWorkloadData(Vec<Job>),
SelectSystemList(Vec<System>),
}

#[derive(Debug, Eq, Clone, PartialOrd, Ord)]
Expand Down
5 changes: 4 additions & 1 deletion coman/src/components/global_listener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use tuirealm::{
};

use crate::app::{
messages::{MenuMsg, Msg},
messages::{MenuMsg, Msg, SystemSelectMsg},
user_events::{CscsEvent, UserEvent},
};

Expand Down Expand Up @@ -34,6 +34,9 @@ impl Component<Msg, UserEvent> for GlobalListener {
Event::User(UserEvent::Cscs(CscsEvent::LoggedIn)) => {
Some(Msg::Info("Successfully logged in".to_string()))
}
Event::User(UserEvent::Cscs(CscsEvent::SelectSystemList(systems))) => {
Some(Msg::SystemSelectPopup(SystemSelectMsg::Opened(systems)))
}
_ => None,
}
}
Expand Down
4 changes: 2 additions & 2 deletions coman/src/components/login_popup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl LoginPopup {
Layout::default()
.constraints(&[Constraint::Length(3), Constraint::Length(3)])
.direction(LayoutDirection::Vertical)
.margin(2),
.margin(1),
)
}

Expand Down Expand Up @@ -179,7 +179,7 @@ impl Component<Msg, UserEvent> for LoginPopup {
}) => self.perform(Cmd::Delete),
Event::Keyboard(KeyEvent {
code: Key::Char(ch),
modifiers: KeyModifiers::NONE,
..
}) => self.perform(Cmd::Type(ch)),
Event::Keyboard(KeyEvent { code: Key::Tab, .. }) => {
self.focus_next();
Expand Down
1 change: 1 addition & 0 deletions coman/src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub(crate) mod error_popup;
pub(crate) mod global_listener;
pub(crate) mod info_popup;
pub(crate) mod login_popup;
pub(crate) mod system_select_popup;
pub(crate) mod toolbar;
pub(crate) mod workload_list;
pub(crate) mod workload_menu;
105 changes: 105 additions & 0 deletions coman/src/components/system_select_popup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use tui_realm_stdlib::List;
use tuirealm::{
Component, Event, Frame, MockComponent, State, StateValue,
command::{Cmd, CmdResult, Direction, Position},
event::{Key, KeyEvent, KeyModifiers},
props::{
Alignment, AttrValue, Attribute, BorderType, Borders, Color, InputType, Layout, Props,
Style, TableBuilder, TextSpan,
},
ratatui::{
layout::{Constraint, Direction as LayoutDirection, Rect},
widgets::Block,
},
};

use crate::{
app::{
messages::{Msg, SystemSelectMsg},
user_events::UserEvent,
},
cscs::api_client::System,
};

#[derive(MockComponent)]
pub struct SystemSelectPopup {
component: List,
systems: Vec<System>,
}

impl SystemSelectPopup {
pub fn new(systems: Vec<System>) -> Self {
let mut rows = TableBuilder::default();
for system in systems.clone() {
rows.add_col(TextSpan::from(system.name).fg(Color::Cyan))
.add_row();
}
Self {
component: List::default()
.borders(
Borders::default()
.modifiers(BorderType::Thick)
.color(Color::Green),
)
.title("Select System", Alignment::Left)
.scroll(true)
.highlighted_color(Color::LightYellow)
.highlighted_str("-")
.rewind(true)
.step(4)
.rows(rows.build()),
systems,
}
}
}

impl Component<Msg, UserEvent> for SystemSelectPopup {
fn on(&mut self, ev: Event<UserEvent>) -> Option<Msg> {
let _ = match ev {
Event::Keyboard(KeyEvent {
code: Key::Down, ..
}) => self.perform(Cmd::Move(Direction::Down)),
Event::Keyboard(KeyEvent {
code: Key::PageDown,
..
}) => self.perform(Cmd::Move(Direction::Down)),
Event::Keyboard(KeyEvent { code: Key::Up, .. }) => {
self.perform(Cmd::Move(Direction::Up))
}
Event::Keyboard(KeyEvent {
code: Key::PageUp, ..
}) => self.perform(Cmd::Move(Direction::Up)),
Event::Keyboard(KeyEvent {
code: Key::Home, ..
}) => self.perform(Cmd::GoTo(Position::Begin)),
Event::Keyboard(KeyEvent { code: Key::End, .. }) => {
self.perform(Cmd::GoTo(Position::End))
}
Event::Keyboard(KeyEvent { code: Key::Esc, .. }) => {
return Some(Msg::SystemSelectPopup(SystemSelectMsg::Closed));
}
Event::Keyboard(KeyEvent {
code: Key::Char('x'),
..
}) => {
return Some(Msg::SystemSelectPopup(SystemSelectMsg::Closed));
}
Event::Keyboard(KeyEvent {
code: Key::Enter, ..
}) => {
let msg = if let State::One(StateValue::Usize(index)) = self.state() {
let selected_system = self.systems[index].clone();
Some(Msg::SystemSelectPopup(SystemSelectMsg::SystemSelected(
selected_system.name,
)))
} else {
Some(Msg::SystemSelectPopup(SystemSelectMsg::Closed))
};
return msg;
}

_ => CmdResult::None,
};
Some(Msg::None)
}
}
26 changes: 15 additions & 11 deletions coman/src/components/workload_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,23 @@ impl Component<Msg, UserEvent> for WorkloadList {
self.perform(Cmd::GoTo(Position::End))
}
Event::User(UserEvent::Cscs(CscsEvent::GotWorkloadData(data))) => {
let mut table = TableBuilder::default();
for (idx, job) in data.iter().enumerate() {
if idx > 0 {
table.add_row();
if data.len() == 0 {
self.attr(Attribute::Content, AttrValue::Table(vec![]));
} else {
let mut table = TableBuilder::default();
for (idx, job) in data.iter().enumerate() {
if idx > 0 {
table.add_row();
}
table
.add_col(TextSpan::from(job.name.clone()).bold())
.add_col(TextSpan::from(" "))
.add_col(TextSpan::from(job.status.to_string()))
.add_col(TextSpan::from(" "))
.add_col(TextSpan::from(job.id.to_string()));
}
table
.add_col(TextSpan::from(job.name.clone()).bold())
.add_col(TextSpan::from(" "))
.add_col(TextSpan::from(job.status.to_string()))
.add_col(TextSpan::from(" "))
.add_col(TextSpan::from(job.id.to_string()));
self.attr(Attribute::Content, AttrValue::Table(table.build()));
}
self.attr(Attribute::Content, AttrValue::Table(table.build()));
self.perform(Cmd::Change)
}
_ => CmdResult::None,
Expand Down
4 changes: 4 additions & 0 deletions coman/src/components/workload_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ impl Default for WorkloadMenu {
TableBuilder::default()
.add_col(TextSpan::from("Login to CSCS").fg(Color::Cyan))
.add_row()
.add_col(TextSpan::from("Switch System").fg(Color::Cyan))
.add_row()
.add_col(TextSpan::from("Quit").fg(Color::Cyan))
.add_row()
.build(),
Expand Down Expand Up @@ -81,6 +83,8 @@ impl Component<Msg, UserEvent> for WorkloadMenu {
let msg = if let State::One(StateValue::Usize(index)) = self.state() {
match index {
0 => Some(Msg::Menu(MenuMsg::CscsLogin)),
1 => Some(Msg::Menu(MenuMsg::CscsSwitchSystem)),
2 => Some(Msg::AppClose),
_ => Some(Msg::Menu(MenuMsg::Closed)),
}
} else {
Expand Down
Loading