config + ui: node server config ui, node restart reminder modal and message

This commit is contained in:
ardocrat 2023-07-01 21:04:52 +03:00
parent 92972fbbd9
commit fc27b77142
6 changed files with 167 additions and 109 deletions

View file

@ -87,11 +87,16 @@ network_settings:
api_secret: Rest API and V2 Owner API token
foreign_api_secret: Foreign API token
disabled: Disabled
enabled: Enabled
copy: Copy
paste: Paste
ftl: The Future Time Limit (FTL)
ftl_description: Limit on how far into the future, relative to a node's local time in seconds, the timestamp on a new block can be, in order for the block to be accepted.
not_valid_value: Entered value is not valid
full_validation: Full validation
full_validation_description: Whether to run a full chain validation when processing each block (except during synchronization).
archive_mode: Archive mode
archive_mode_desc: Run the node in full archive mode (more disk space and time will be required for synchronization).
modal:
cancel: Cancel
save: Save

View file

@ -87,11 +87,16 @@ network_settings:
api_secret: Rest и V2 Owner API токен
foreign_api_secret: Foreign API токен
disabled: Отключен
enabled: Включен
copy: Копировать
paste: Вставить
ftl: Предел Будущего Времени (FTL)
ftl_description: Ограничение на то, насколько далеко в будущем, относительно локального времени узла в секундах, находится временная метка на новом блоке для его принятия.
ftl_description: Насколько далеко в будущем, относительно локального времени узла в секундах, может находиться временная метка на новом блоке для его принятия.
not_valid_value: Введено недопустимое значение
full_validation: Полная валидация
full_validation_description: Запускать ли полную проверку цепи при обработке каждого блока (за исключением синхронизации).
archive_mode: Архивный режим
archive_mode_desc: Запустить узел в режиме полного архива (потребуется больше места и времени для синхронизации).
modal:
cancel: Отмена
save: Сохранить

View file

@ -37,7 +37,8 @@ impl NetworkTab for NetworkMetrics {
fn ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
let server_stats = Node::get_stats();
// Show message when node is not running or loading spinner when metrics are not available.
if server_stats.is_none() || server_stats.as_ref().unwrap().diff_stats.height == 0 {
if server_stats.is_none() || Node::is_restarting()
|| server_stats.as_ref().unwrap().diff_stats.height == 0 {
if !Node::is_running() {
Network::disabled_node_ui(ui);
} else {

View file

@ -17,9 +17,9 @@ use std::str::FromStr;
use egui::{RichText, ScrollArea};
use crate::gui::Colors;
use crate::gui::{Colors, Navigator};
use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::{Modal, NetworkTab, NetworkTabType, View};
use crate::gui::views::{Modal, ModalPosition, NetworkTab, NetworkTabType, View};
use crate::gui::views::settings_node::NodeSetup;
use crate::node::Node;
@ -67,8 +67,30 @@ impl NetworkTab for NetworkSettings {
impl NetworkSettings {
pub const NODE_RESTART_REQUIRED_MODAL: &'static str = "node_restart_required";
/// Reminder to restart enabled node to show on edit setting at [`Modal`].
pub fn node_restart_required_ui(ui: &mut egui::Ui) {
if Node::is_running() {
ui.add_space(12.0);
ui.label(RichText::new(t!("network_settings.restart_node_required"))
.size(16.0)
.color(Colors::GREEN)
);
}
}
/// Show [`Modal`] to ask node restart if setting is changed on enabled node.
pub fn show_node_restart_required_modal() {
if Node::is_running() {
// Show modal to apply changes by node restart.
let port_modal = Modal::new(NetworkSettings::NODE_RESTART_REQUIRED_MODAL)
.position(ModalPosition::Center)
.title(t!("network.settings"));
Navigator::show_modal(port_modal);
}
}
/// Node restart reminder modal content.
pub fn node_restart_required_modal(&self, ui: &mut egui::Ui, modal: &Modal) {
fn node_restart_required_modal(&self, ui: &mut egui::Ui, modal: &Modal) {
ui.add_space(6.0);
ui.vertical_centered(|ui| {
ui.label(RichText::new(t!("network_settings.restart_node_required"))

View file

@ -17,7 +17,7 @@ use egui::{Id, Layout, RichText, TextStyle, Widget};
use grin_core::global::ChainTypes;
use crate::AppConfig;
use crate::gui::{Colors, Navigator};
use crate::gui::icons::{ASTERISK, CLIPBOARD_TEXT, COMPUTER_TOWER, COPY, POWER};
use crate::gui::icons::{CLIPBOARD_TEXT, COMPUTER_TOWER, COPY, POWER, SHIELD, SHIELD_SLASH};
use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::{Modal, ModalPosition, Network, View};
use crate::gui::views::network_settings::NetworkSettings;
@ -138,6 +138,9 @@ impl NodeSetup {
let api_available = NodeConfig::is_api_port_available(selected_ip, &api_port);
self.is_api_port_available = api_available;
NodeConfig::save_api_address(selected_ip, &api_port);
if api_available {
NetworkSettings::show_node_restart_required_modal();
}
});
ui.label(RichText::new(t!("network_settings.api_port"))
@ -165,16 +168,6 @@ impl NodeSetup {
ui.add_space(6.0);
// Show Foreign API secret setup.
self.secret_ui(Self::FOREIGN_API_SECRET_MODAL, ui, cb);
if Node::is_running() {
ui.add_space(2.0);
// Show reminder to restart node if settings are changed.
ui.label(RichText::new(t!("network_settings.restart_node_required"))
.size(16.0)
.color(Colors::GREEN)
);
ui.add_space(2.0);
}
});
}
@ -191,6 +184,21 @@ impl NodeSetup {
// Show FTL setup.
self.ftl_ui(ui, cb);
ui.add_space(6.0);
View::horizontal_line(ui, Colors::ITEM_STROKE);
ui.add_space(6.0);
// Validation setup.
self.validation_mode_ui(ui);
ui.add_space(6.0);
View::horizontal_line(ui, Colors::ITEM_STROKE);
ui.add_space(6.0);
// Archive mode setup.
self.archive_mode_ui(ui);
ui.add_space(6.0);
View::horizontal_line(ui, Colors::ITEM_STROKE);
ui.add_space(6.0);
});
@ -215,13 +223,7 @@ impl NodeSetup {
if saved_chain_type != selected_chain_type {
AppConfig::change_chain_type(&selected_chain_type);
if Node::is_running() {
// Show modal to apply changes by node restart.
let port_modal = Modal::new(NetworkSettings::NODE_RESTART_REQUIRED_MODAL)
.position(ModalPosition::Center)
.title(t!("network.settings"));
Navigator::show_modal(port_modal);
}
NetworkSettings::show_node_restart_required_modal();
}
}
@ -263,7 +265,7 @@ impl NodeSetup {
ui.label(RichText::new(t!("network_settings.api_port"))
.size(18.0)
.color(Colors::GRAY));
ui.add_space(8.0);
ui.add_space(6.0);
// Draw API port text edit.
let text_edit_resp = egui::TextEdit::singleline(&mut self.api_port_edit)
@ -276,51 +278,52 @@ impl NodeSetup {
cb.show_keyboard();
}
// Show error when specified port is unavailable.
// Show error when specified port is unavailable or reminder to restart enabled node.
if !self.api_port_available_edit {
ui.add_space(12.0);
ui.label(RichText::new(t!("network_settings.port_unavailable"))
.size(16.0)
.color(Colors::RED));
} else {
NetworkSettings::node_restart_required_ui(ui);
}
ui.add_space(12.0);
});
// Show modal buttons.
ui.scope(|ui| {
// Setup spacing between buttons.
ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0);
// Show modal buttons.
ui.scope(|ui| {
// Setup spacing between buttons.
ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0);
// Save button callback.
let on_save = || {
// Check if port is available.
let (api_ip, _) = NodeConfig::get_api_address();
let available = NodeConfig::is_api_port_available(&api_ip, &self.api_port_edit);
self.api_port_available_edit = available;
// Save button callback.
let on_save = || {
// Check if port is available.
let (api_ip, _) = NodeConfig::get_api_address();
let available = NodeConfig::is_api_port_available(&api_ip, &self.api_port_edit);
self.api_port_available_edit = available;
if available {
// Save port at config if it's available.
NodeConfig::save_api_address(&api_ip, &self.api_port_edit);
if available {
// Save port at config if it's available.
NodeConfig::save_api_address(&api_ip, &self.api_port_edit);
self.is_api_port_available = true;
self.is_api_port_available = true;
cb.hide_keyboard();
modal.close();
}
};
ui.columns(2, |columns| {
columns[0].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.cancel"), Colors::WHITE, || {
cb.hide_keyboard();
modal.close();
}
};
ui.columns(2, |columns| {
columns[0].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.cancel"), Colors::WHITE, || {
cb.hide_keyboard();
modal.close();
});
});
columns[1].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.save"), Colors::WHITE, on_save);
});
});
ui.add_space(6.0);
columns[1].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.save"), Colors::WHITE, on_save);
});
});
ui.add_space(6.0);
});
}
@ -333,10 +336,9 @@ impl NodeSetup {
};
let secret_text = if secret_value.is_some() {
format!("{}{}{}{}{}{}{}{}{}{}", ASTERISK, ASTERISK, ASTERISK, ASTERISK,
ASTERISK, ASTERISK, ASTERISK, ASTERISK, ASTERISK, ASTERISK)
format!("{} {}", SHIELD, t!("network_settings.enabled"))
} else {
t!("network_settings.disabled")
format!("{} {}", SHIELD_SLASH, t!("network_settings.disabled"))
};
// Show button to open secret modal.
@ -373,8 +375,6 @@ impl NodeSetup {
.color(Colors::GRAY));
ui.add_space(8.0);
// let Self { api_secret_edit, foreign_api_secret_edit, .. } = self;
// Draw API port text edit.
let edit_text = match modal.id {
Self::API_SECRET_MODAL => &mut self.api_secret_edit,
@ -389,6 +389,7 @@ impl NodeSetup {
if text_edit_resp.clicked() {
cb.show_keyboard();
}
ui.add_space(12.0);
// Show buttons to copy/paste text.
@ -397,10 +398,9 @@ impl NodeSetup {
ui.spacing_mut().item_spacing = egui::Vec2::new(12.0, 0.0);
ui.columns(2, |columns| {
// Setup spacing between buttons.
columns[0].with_layout(Layout::right_to_left(Align::TOP), |ui| {
let copy_text = format!("{} {}", COPY, t!("network_settings.copy"));
View::button(ui, copy_text, Colors::WHITE, || {
let copy_title = format!("{} {}", COPY, t!("network_settings.copy"));
View::button(ui, copy_title, Colors::WHITE, || {
match modal.id {
Self::API_SECRET_MODAL => {
cb.copy_string_to_buffer(self.api_secret_edit.clone());
@ -413,8 +413,10 @@ impl NodeSetup {
});
});
columns[1].with_layout(Layout::left_to_right(Align::TOP), |ui| {
let copy_text = format!("{} {}", CLIPBOARD_TEXT, t!("network_settings.paste"));
View::button(ui, copy_text, Colors::WHITE, || {
let paste_title = format!("{} {}",
CLIPBOARD_TEXT,
t!("network_settings.paste"));
View::button(ui, paste_title, Colors::WHITE, || {
let text = cb.get_string_from_buffer();
match modal.id {
Self::API_SECRET_MODAL => self.api_secret_edit = text,
@ -423,43 +425,47 @@ impl NodeSetup {
});
});
});
ui.add_space(12.0);
});
// Show modal buttons.
ui.scope(|ui| {
// Setup spacing between buttons.
ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0);
// Show reminder to restart enabled node.
NetworkSettings::node_restart_required_ui(ui);
// Save button callback.
let on_save = || {
match modal.id {
Self::API_SECRET_MODAL => {
let api_secret = &self.api_secret_edit.clone();
NodeConfig::save_api_secret(api_secret);
}
_ => {
let foreign_api_secret = &self.foreign_api_secret_edit.clone();
NodeConfig::save_foreign_api_secret(foreign_api_secret);
}
};
cb.hide_keyboard();
modal.close();
ui.add_space(12.0);
});
// Show modal buttons.
ui.scope(|ui| {
// Setup spacing between buttons.
ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0);
// Save button callback.
let on_save = || {
match modal.id {
Self::API_SECRET_MODAL => {
let api_secret = &self.api_secret_edit.clone();
NodeConfig::save_api_secret(api_secret);
}
_ => {
let foreign_api_secret = &self.foreign_api_secret_edit.clone();
NodeConfig::save_foreign_api_secret(foreign_api_secret);
}
};
cb.hide_keyboard();
modal.close();
};
ui.columns(2, |columns| {
columns[0].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.cancel"), Colors::WHITE, || {
cb.hide_keyboard();
modal.close();
});
});
columns[1].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.save"), Colors::WHITE, on_save);
ui.columns(2, |columns| {
columns[0].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.cancel"), Colors::WHITE, || {
cb.hide_keyboard();
modal.close();
});
});
ui.add_space(6.0);
columns[1].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.save"), Colors::WHITE, on_save);
});
});
ui.add_space(6.0);
});
}
@ -482,16 +488,6 @@ impl NodeSetup {
.size(16.0)
.color(Colors::INACTIVE_TEXT)
);
if Node::is_running() {
ui.add_space(2.0);
// Show reminder to restart node if settings are changed.
ui.label(RichText::new(t!("network_settings.restart_node_required"))
.size(16.0)
.color(Colors::GREEN)
);
ui.add_space(2.0);
}
ui.add_space(6.0);
}
@ -508,7 +504,7 @@ impl NodeSetup {
let text_edit_resp = egui::TextEdit::singleline(&mut self.ftl_edit)
.id(Id::from(modal.id))
.font(TextStyle::Heading)
.desired_width(34.0)
.desired_width(46.0)
.cursor_at_end(true)
.ui(ui);
text_edit_resp.request_focus();
@ -516,17 +512,18 @@ impl NodeSetup {
cb.show_keyboard();
}
// Show error when specified value is not valid.
// Show error when specified value is not valid or reminder to restart enabled node.
if self.ftl_edit.parse::<u64>().is_err() {
ui.add_space(12.0);
ui.label(RichText::new(t!("network_settings.not_valid_value"))
.size(18.0)
.color(Colors::RED));
} else {
NetworkSettings::node_restart_required_ui(ui);
}
ui.add_space(12.0);
});
ui.add_space(12.0);
// Show modal buttons.
ui.scope(|ui| {
// Setup spacing between buttons.
@ -556,4 +553,32 @@ impl NodeSetup {
ui.add_space(6.0);
});
}
/// Draw chain validation mode setup ui.
pub fn validation_mode_ui(&mut self, ui: &mut egui::Ui) {
let validate = NodeConfig::is_full_chain_validation();
View::checkbox(ui, validate, t!("network_settings.full_validation"), || {
NodeConfig::toggle_full_chain_validation();
NetworkSettings::show_node_restart_required_modal();
});
ui.add_space(6.0);
ui.label(RichText::new(t!("network_settings.full_validation_description"))
.size(16.0)
.color(Colors::INACTIVE_TEXT)
);
}
/// Draw archive mode setup ui.
pub fn archive_mode_ui(&mut self, ui: &mut egui::Ui) {
let archive_mode = NodeConfig::is_archive_mode();
View::checkbox(ui, archive_mode, t!("network_settings.archive_mode"), || {
NodeConfig::toggle_archive_mode();
NetworkSettings::show_node_restart_required_modal();
});
ui.add_space(6.0);
ui.label(RichText::new(t!("network_settings.archive_mode_desc"))
.size(16.0)
.color(Colors::INACTIVE_TEXT)
);
}
}

View file

@ -340,9 +340,9 @@ impl NodeConfig {
}
/// Toggle full chain validation.
pub fn toggle_chain_validation() {
let mode = Settings::node_config_to_read().members.clone().server.chain_validation_mode;
let new_mode = if mode == ChainValidationMode::Disabled {
pub fn toggle_full_chain_validation() {
let validation_enabled = Self::is_full_chain_validation();
let new_mode = if validation_enabled {
ChainValidationMode::Disabled
} else {
ChainValidationMode::EveryBlock