use std::borrow::Cow;
use rust_i18n::t;
use super::ResourceTab;
const DEFAULT_SUBNET_V4: &str = "192.168.0.0/24";
const DEFAULT_LOCATION: &str = "ru-1";
const DEFAULT_DRIVE_SIZE_GB: &str = "10";
const DEFAULT_DRIVE_TYPE: &str = "nvme";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InputField {
pub label: String,
pub value: String,
pub required: bool
}
impl InputField {
fn required(label: Cow<'_, str>) -> Self {
Self {
label: label.into_owned(),
value: String::new(),
required: true
}
}
fn optional(label: Cow<'_, str>) -> Self {
Self {
label: label.into_owned(),
value: String::new(),
required: false
}
}
fn prefilled(label: Cow<'_, str>, value: &str) -> Self {
Self {
label: label.into_owned(),
value: value.to_string(),
required: true
}
}
}
pub fn parse_size_gb(value: &str) -> Result<f64, String> {
let trimmed = value.trim();
match trimmed.parse::<f64>() {
Ok(size) if size > 0.0 && size.is_finite() => Ok(size),
_ => Err(t!("form.invalid_size", value => trimmed).into_owned())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CreateForm {
pub tab: ResourceTab,
pub title: String,
pub fields: Vec<InputField>,
pub active: usize
}
impl super::App {
#[must_use]
pub const fn create_form_open(&self) -> bool {
self.create_form.is_some()
}
fn build_create_form(tab: ResourceTab) -> Option<CreateForm> {
let fields = match tab {
ResourceTab::Projects => vec![
InputField::required(t!("form.field.name")),
InputField::optional(t!("form.field.description")),
],
ResourceTab::SshKeys => vec![
InputField::required(t!("form.field.name")),
InputField::required(t!("form.field.public_key")),
],
ResourceTab::Vpc => vec![
InputField::required(t!("form.field.name")),
InputField::prefilled(t!("form.field.subnet"), DEFAULT_SUBNET_V4),
InputField::prefilled(t!("form.field.location"), DEFAULT_LOCATION),
],
ResourceTab::NetworkDrives => vec![
InputField::required(t!("form.field.name")),
InputField::prefilled(t!("form.field.size_gb"), DEFAULT_DRIVE_SIZE_GB),
InputField::prefilled(t!("form.field.drive_type"), DEFAULT_DRIVE_TYPE),
],
_ => return None
};
Some(CreateForm {
tab,
title: crate::tui::widgets::service_header::texts(tab)
.1
.into_owned(),
fields,
active: 0
})
}
#[must_use]
pub fn tab_has_create_form(tab: ResourceTab) -> bool {
Self::build_create_form(tab).is_some()
}
pub fn open_create_form(&mut self) {
if let Some(form) = Self::build_create_form(self.active_tab) {
self.create_form = Some(form);
} else {
self.status_message = Some(t!("app.create_not_supported").to_string());
}
}
pub fn close_create_form(&mut self) {
self.create_form = None;
}
pub const fn form_next_field(&mut self) {
if let Some(form) = &mut self.create_form
&& !form.fields.is_empty()
{
form.active = (form.active + 1) % form.fields.len();
}
}
pub const fn form_prev_field(&mut self) {
if let Some(form) = &mut self.create_form
&& !form.fields.is_empty()
{
let len = form.fields.len();
form.active = (form.active + len - 1) % len;
}
}
pub fn form_input(&mut self, c: char) {
if let Some(form) = &mut self.create_form
&& let Some(field) = form.fields.get_mut(form.active)
{
field.value.push(c);
}
}
pub fn form_backspace(&mut self) {
if let Some(form) = &mut self.create_form
&& let Some(field) = form.fields.get_mut(form.active)
{
field.value.pop();
}
}
pub fn form_submit(&mut self) -> bool {
let Some(form) = &self.create_form else {
return false;
};
if form
.fields
.iter()
.any(|f| f.required && f.value.trim().is_empty())
{
return false;
}
self.create_request = self.create_form.take();
true
}
pub const fn take_create_request(&mut self) -> Option<CreateForm> {
self.create_request.take()
}
}