Moved file transfer protocol input on top; port will now be set to default for current protocol on change

This commit is contained in:
veeso
2021-05-05 22:05:46 +02:00
parent dcec804681
commit 4f1e505a7a
5 changed files with 184 additions and 90 deletions

View File

@@ -30,6 +30,9 @@ Released on FIXME: ??
- Enhancements - Enhancements
- Added a status bar in the file explorer showing whether the sync browser is enabled and which file sorting mode is selected - Added a status bar in the file explorer showing whether the sync browser is enabled and which file sorting mode is selected
- Removed the goold old figlet title - Removed the goold old figlet title
- Protocol input as first field in UI
- Port is now updated to standard for selected protocol
- when you change the protocol in the authentication form and the current port is standard (`< 1024`), the port will be automatically changed to default value for the selected protocol (e.g. current port: `123`, protocol is changes to `FTP`, port becomes `21`)
- Bugfix: - Bugfix:
- Fixed wrong text wrap in log box - Fixed wrong text wrap in log box
- Fixed error message not being shown after an upload failure - Fixed error message not being shown after an upload failure

View File

@@ -0,0 +1,71 @@
//! ## AuthActivity
//!
//! `auth_activity` is the module which implements the authentication activity
/**
* MIT License
*
* termscp - Copyright (c) 2021 Christian Visintin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use super::{AuthActivity, FileTransferProtocol};
impl AuthActivity {
/// ### protocol_opt_to_enum
///
/// Convert radio index for protocol into a `FileTransferProtocol`
pub(super) fn protocol_opt_to_enum(protocol: usize) -> FileTransferProtocol {
match protocol {
1 => FileTransferProtocol::Scp,
2 => FileTransferProtocol::Ftp(false),
3 => FileTransferProtocol::Ftp(true),
_ => FileTransferProtocol::Sftp,
}
}
/// ### protocol_enum_to_opt
///
/// Convert `FileTransferProtocol` enum into radio group index
pub(super) fn protocol_enum_to_opt(protocol: FileTransferProtocol) -> usize {
match protocol {
FileTransferProtocol::Sftp => 0,
FileTransferProtocol::Scp => 1,
FileTransferProtocol::Ftp(false) => 2,
FileTransferProtocol::Ftp(true) => 3,
}
}
/// ### get_default_port_for_protocol
///
/// Get the default port for protocol
pub(super) fn get_default_port_for_protocol(protocol: FileTransferProtocol) -> u16 {
match protocol {
FileTransferProtocol::Sftp | FileTransferProtocol::Scp => 22,
FileTransferProtocol::Ftp(_) => 21,
}
}
/// ### is_port_standard
///
/// Returns whether the port is standard or not
pub(super) fn is_port_standard(port: u16) -> bool {
port < 1024
}
}

View File

@@ -27,6 +27,7 @@
*/ */
// Sub modules // Sub modules
mod bookmarks; mod bookmarks;
mod misc;
mod update; mod update;
mod view; mod view;

View File

@@ -27,15 +27,16 @@
*/ */
// locals // locals
use super::{ use super::{
AuthActivity, FileTransferParams, COMPONENT_BOOKMARKS_LIST, COMPONENT_INPUT_ADDR, AuthActivity, FileTransferParams, FileTransferProtocol, COMPONENT_BOOKMARKS_LIST,
COMPONENT_INPUT_BOOKMARK_NAME, COMPONENT_INPUT_PASSWORD, COMPONENT_INPUT_PORT, COMPONENT_INPUT_ADDR, COMPONENT_INPUT_BOOKMARK_NAME, COMPONENT_INPUT_PASSWORD,
COMPONENT_INPUT_USERNAME, COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK, COMPONENT_INPUT_PORT, COMPONENT_INPUT_USERNAME, COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK,
COMPONENT_RADIO_BOOKMARK_DEL_RECENT, COMPONENT_RADIO_BOOKMARK_SAVE_PWD, COMPONENT_RADIO_BOOKMARK_DEL_RECENT, COMPONENT_RADIO_BOOKMARK_SAVE_PWD,
COMPONENT_RADIO_PROTOCOL, COMPONENT_RADIO_QUIT, COMPONENT_RECENTS_LIST, COMPONENT_TEXT_ERROR, COMPONENT_RADIO_PROTOCOL, COMPONENT_RADIO_QUIT, COMPONENT_RECENTS_LIST, COMPONENT_TEXT_ERROR,
COMPONENT_TEXT_HELP, COMPONENT_TEXT_HELP,
}; };
use crate::ui::activities::keymap::*; use crate::ui::activities::keymap::*;
use tuirealm::{Msg, Payload, Value}; use tuirealm::components::InputPropsBuilder;
use tuirealm::{Msg, Payload, PropsBuilder, Value};
// -- update // -- update
@@ -51,17 +52,17 @@ impl AuthActivity {
None => None, // Exit after None None => None, // Exit after None
Some(msg) => match msg { Some(msg) => match msg {
// Focus ( DOWN ) // Focus ( DOWN )
(COMPONENT_RADIO_PROTOCOL, &MSG_KEY_DOWN) => {
// Give focus to port
self.view.active(COMPONENT_INPUT_ADDR);
None
}
(COMPONENT_INPUT_ADDR, &MSG_KEY_DOWN) => { (COMPONENT_INPUT_ADDR, &MSG_KEY_DOWN) => {
// Give focus to port // Give focus to port
self.view.active(COMPONENT_INPUT_PORT); self.view.active(COMPONENT_INPUT_PORT);
None None
} }
(COMPONENT_INPUT_PORT, &MSG_KEY_DOWN) => { (COMPONENT_INPUT_PORT, &MSG_KEY_DOWN) => {
// Give focus to port
self.view.active(COMPONENT_RADIO_PROTOCOL);
None
}
(COMPONENT_RADIO_PROTOCOL, &MSG_KEY_DOWN) => {
// Give focus to port // Give focus to port
self.view.active(COMPONENT_INPUT_USERNAME); self.view.active(COMPONENT_INPUT_USERNAME);
None None
@@ -73,7 +74,7 @@ impl AuthActivity {
} }
(COMPONENT_INPUT_PASSWORD, &MSG_KEY_DOWN) => { (COMPONENT_INPUT_PASSWORD, &MSG_KEY_DOWN) => {
// Give focus to port // Give focus to port
self.view.active(COMPONENT_INPUT_ADDR); self.view.active(COMPONENT_RADIO_PROTOCOL);
None None
} }
// Focus ( UP ) // Focus ( UP )
@@ -83,11 +84,6 @@ impl AuthActivity {
None None
} }
(COMPONENT_INPUT_USERNAME, &MSG_KEY_UP) => { (COMPONENT_INPUT_USERNAME, &MSG_KEY_UP) => {
// Give focus to port
self.view.active(COMPONENT_RADIO_PROTOCOL);
None
}
(COMPONENT_RADIO_PROTOCOL, &MSG_KEY_UP) => {
// Give focus to port // Give focus to port
self.view.active(COMPONENT_INPUT_PORT); self.view.active(COMPONENT_INPUT_PORT);
None None
@@ -98,10 +94,28 @@ impl AuthActivity {
None None
} }
(COMPONENT_INPUT_ADDR, &MSG_KEY_UP) => { (COMPONENT_INPUT_ADDR, &MSG_KEY_UP) => {
// Give focus to port
self.view.active(COMPONENT_RADIO_PROTOCOL);
None
}
(COMPONENT_RADIO_PROTOCOL, &MSG_KEY_UP) => {
// Give focus to port // Give focus to port
self.view.active(COMPONENT_INPUT_PASSWORD); self.view.active(COMPONENT_INPUT_PASSWORD);
None None
} }
// Protocol - On Change
(COMPONENT_RADIO_PROTOCOL, Msg::OnChange(Payload::One(Value::Usize(protocol)))) => {
// If port is standard, update the current port with default for selected protocol
let protocol: FileTransferProtocol = Self::protocol_opt_to_enum(*protocol);
// Get port
let port: u16 = self.get_input_port();
match Self::is_port_standard(port) {
false => None, // Return None
true => {
self.update_input_port(Self::get_default_port_for_protocol(protocol))
}
}
}
// <TAB> bookmarks // <TAB> bookmarks
(COMPONENT_BOOKMARKS_LIST, &MSG_KEY_TAB) (COMPONENT_BOOKMARKS_LIST, &MSG_KEY_TAB)
| (COMPONENT_RECENTS_LIST, &MSG_KEY_TAB) => { | (COMPONENT_RECENTS_LIST, &MSG_KEY_TAB) => {
@@ -322,4 +336,16 @@ impl AuthActivity {
}, },
} }
} }
fn update_input_port(&mut self, port: u16) -> Option<(String, Msg)> {
match self.view.get_props(COMPONENT_INPUT_PORT) {
None => None,
Some(props) => {
let props = InputPropsBuilder::from(props)
.with_value(port.to_string())
.build();
self.view.update(COMPONENT_INPUT_PORT, props)
}
}
}
} }

View File

@@ -99,42 +99,12 @@ impl AuthActivity {
.build(), .build(),
)), )),
); );
// Address
self.view.mount(
super::COMPONENT_INPUT_ADDR,
Box::new(Input::new(
InputPropsBuilder::default()
.with_foreground(Color::Yellow)
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightYellow)
.with_label(String::from("Remote address"))
.build(),
)),
);
// Get default protocol // Get default protocol
let default_protocol: FileTransferProtocol = let default_protocol: FileTransferProtocol =
match self.context.as_ref().unwrap().config_client.as_ref() { match self.context.as_ref().unwrap().config_client.as_ref() {
Some(cli) => cli.get_default_protocol(), Some(cli) => cli.get_default_protocol(),
None => FileTransferProtocol::Sftp, None => FileTransferProtocol::Sftp,
}; };
// Calc default port
let default_port: String = String::from(match default_protocol {
FileTransferProtocol::Ftp(_) => "21",
FileTransferProtocol::Sftp | FileTransferProtocol::Scp => "22",
});
// Port
self.view.mount(
super::COMPONENT_INPUT_PORT,
Box::new(Input::new(
InputPropsBuilder::default()
.with_foreground(Color::LightCyan)
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightCyan)
.with_label(String::from("Port number"))
.with_input(InputType::Number)
.with_input_len(5)
.with_value(default_port)
.build(),
)),
);
// Protocol // Protocol
self.view.mount( self.view.mount(
super::COMPONENT_RADIO_PROTOCOL, super::COMPONENT_RADIO_PROTOCOL,
@@ -156,6 +126,36 @@ impl AuthActivity {
.build(), .build(),
)), )),
); );
// Address
self.view.mount(
super::COMPONENT_INPUT_ADDR,
Box::new(Input::new(
InputPropsBuilder::default()
.with_foreground(Color::Yellow)
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightYellow)
.with_label(String::from("Remote address"))
.build(),
)),
);
// Calc default port
let default_port: String = String::from(match default_protocol {
FileTransferProtocol::Ftp(_) => "21",
FileTransferProtocol::Sftp | FileTransferProtocol::Scp => "22",
});
// Port
self.view.mount(
super::COMPONENT_INPUT_PORT,
Box::new(Input::new(
InputPropsBuilder::default()
.with_foreground(Color::LightCyan)
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightCyan)
.with_label(String::from("Port number"))
.with_input(InputType::Number)
.with_input_len(5)
.with_value(default_port)
.build(),
)),
);
// Username // Username
self.view.mount( self.view.mount(
super::COMPONENT_INPUT_USERNAME, super::COMPONENT_INPUT_USERNAME,
@@ -229,8 +229,8 @@ impl AuthActivity {
)), )),
); );
let _ = self.view_recent_connections(); let _ = self.view_recent_connections();
// Active address // Active protocol
self.view.active(super::COMPONENT_INPUT_ADDR); self.view.active(super::COMPONENT_RADIO_PROTOCOL);
} }
/// ### view /// ### view
@@ -258,9 +258,9 @@ impl AuthActivity {
Constraint::Length(1), // h1 Constraint::Length(1), // h1
Constraint::Length(1), // h2 Constraint::Length(1), // h2
Constraint::Length(1), // Version Constraint::Length(1), // Version
Constraint::Length(3), // protocol
Constraint::Length(3), // host Constraint::Length(3), // host
Constraint::Length(3), // port Constraint::Length(3), // port
Constraint::Length(3), // protocol
Constraint::Length(3), // username Constraint::Length(3), // username
Constraint::Length(3), // password Constraint::Length(3), // password
Constraint::Length(3), // footer Constraint::Length(3), // footer
@@ -283,11 +283,11 @@ impl AuthActivity {
self.view self.view
.render(super::COMPONENT_TEXT_NEW_VERSION, f, auth_chunks[2]); .render(super::COMPONENT_TEXT_NEW_VERSION, f, auth_chunks[2]);
self.view self.view
.render(super::COMPONENT_INPUT_ADDR, f, auth_chunks[3]); .render(super::COMPONENT_RADIO_PROTOCOL, f, auth_chunks[3]);
self.view self.view
.render(super::COMPONENT_INPUT_PORT, f, auth_chunks[4]); .render(super::COMPONENT_INPUT_ADDR, f, auth_chunks[4]);
self.view self.view
.render(super::COMPONENT_RADIO_PROTOCOL, f, auth_chunks[5]); .render(super::COMPONENT_INPUT_PORT, f, auth_chunks[5]);
self.view self.view
.render(super::COMPONENT_INPUT_USERNAME, f, auth_chunks[6]); .render(super::COMPONENT_INPUT_USERNAME, f, auth_chunks[6]);
self.view self.view
@@ -716,53 +716,46 @@ impl AuthActivity {
/// ///
/// Collect input values from view /// Collect input values from view
pub(super) fn get_input(&self) -> (String, u16, FileTransferProtocol, String, String) { pub(super) fn get_input(&self) -> (String, u16, FileTransferProtocol, String, String) {
let addr: String = match self.view.get_state(super::COMPONENT_INPUT_ADDR) { let addr: String = self.get_input_addr();
Some(Payload::One(Value::Str(a))) => a, let port: u16 = self.get_input_port();
_ => String::new(), let protocol: FileTransferProtocol = self.get_input_protocol();
}; let username: String = self.get_input_username();
let port: u16 = match self.view.get_state(super::COMPONENT_INPUT_PORT) { let password: String = self.get_input_password();
Some(Payload::One(Value::Usize(p))) => p as u16,
_ => 0,
};
let protocol: FileTransferProtocol =
match self.view.get_state(super::COMPONENT_RADIO_PROTOCOL) {
Some(Payload::One(Value::Usize(p))) => Self::protocol_opt_to_enum(p),
_ => FileTransferProtocol::Sftp,
};
let username: String = match self.view.get_state(super::COMPONENT_INPUT_USERNAME) {
Some(Payload::One(Value::Str(a))) => a,
_ => String::new(),
};
let password: String = match self.view.get_state(super::COMPONENT_INPUT_PASSWORD) {
Some(Payload::One(Value::Str(a))) => a,
_ => String::new(),
};
(addr, port, protocol, username, password) (addr, port, protocol, username, password)
} }
// -- utils pub(super) fn get_input_addr(&self) -> String {
match self.view.get_state(super::COMPONENT_INPUT_ADDR) {
Some(Payload::One(Value::Str(x))) => x,
_ => String::new(),
}
}
/// ### protocol_opt_to_enum pub(super) fn get_input_port(&self) -> u16 {
/// match self.view.get_state(super::COMPONENT_INPUT_PORT) {
/// Convert radio index for protocol into a `FileTransferProtocol` Some(Payload::One(Value::Usize(x))) => x as u16,
pub(crate) fn protocol_opt_to_enum(protocol: usize) -> FileTransferProtocol { _ => Self::get_default_port_for_protocol(FileTransferProtocol::Sftp),
match protocol { }
1 => FileTransferProtocol::Scp, }
2 => FileTransferProtocol::Ftp(false),
3 => FileTransferProtocol::Ftp(true), pub(super) fn get_input_protocol(&self) -> FileTransferProtocol {
match self.view.get_state(super::COMPONENT_RADIO_PROTOCOL) {
Some(Payload::One(Value::Usize(x))) => Self::protocol_opt_to_enum(x),
_ => FileTransferProtocol::Sftp, _ => FileTransferProtocol::Sftp,
} }
} }
/// ### protocol_enum_to_opt pub(super) fn get_input_username(&self) -> String {
/// match self.view.get_state(super::COMPONENT_INPUT_USERNAME) {
/// Convert `FileTransferProtocol` enum into radio group index Some(Payload::One(Value::Str(x))) => x,
pub(crate) fn protocol_enum_to_opt(protocol: FileTransferProtocol) -> usize { _ => String::new(),
match protocol { }
FileTransferProtocol::Sftp => 0, }
FileTransferProtocol::Scp => 1,
FileTransferProtocol::Ftp(false) => 2, pub(super) fn get_input_password(&self) -> String {
FileTransferProtocol::Ftp(true) => 3, match self.view.get_state(super::COMPONENT_INPUT_PASSWORD) {
Some(Payload::One(Value::Str(x))) => x,
_ => String::new(),
} }
} }
} }