Compare commits

..

4 Commits

Author SHA1 Message Date
Dark-Alex-17 3be7b09da8 feat: Added config option to filter for specific disk space paths to display in the UI (CLI is unaffected) 2026-01-22 10:49:30 -07:00
Dark-Alex-17 5f3123cd79 test: Updated snapshot tests to assert the paths are updated in the UI
Check / stable / fmt (push) Successful in 9m57s
Check / beta / clippy (push) Successful in 10m59s
Check / stable / clippy (push) Successful in 10m59s
Check / nightly / doc (push) Successful in 59s
Check / 1.89.0 / check (push) Successful in 1m7s
Test Suite / ubuntu / beta (push) Successful in 1m48s
Test Suite / ubuntu / stable (push) Successful in 1m43s
Test Suite / ubuntu / stable / coverage (push) Successful in 12m55s
Test Suite / macos-latest / stable (push) Has been cancelled
Test Suite / windows-latest / stable (push) Has been cancelled
2026-01-22 09:39:44 -07:00
Dark-Alex-17 d8f7febfe1 feat: Improved disk-space UI and CLI that shows the actual path being monitored instead of just a disk number
Check / stable / fmt (push) Has been cancelled
Check / beta / clippy (push) Has been cancelled
Check / stable / clippy (push) Has been cancelled
Check / nightly / doc (push) Has been cancelled
Check / 1.89.0 / check (push) Has been cancelled
Test Suite / ubuntu / beta (push) Has been cancelled
Test Suite / ubuntu / stable (push) Has been cancelled
Test Suite / macos-latest / stable (push) Has been cancelled
Test Suite / windows-latest / stable (push) Has been cancelled
Test Suite / ubuntu / stable / coverage (push) Has been cancelled
2026-01-22 09:36:58 -07:00
Dark-Alex-17 0bfbb44e3e feat: Implemented the forgotten lidarr list disk-space command
Check / stable / fmt (push) Successful in 9m59s
Check / beta / clippy (push) Successful in 10m58s
Check / stable / clippy (push) Has been cancelled
Check / nightly / doc (push) Has been cancelled
Check / 1.89.0 / check (push) Has been cancelled
Test Suite / ubuntu / beta (push) Has been cancelled
Test Suite / ubuntu / stable (push) Has been cancelled
Test Suite / macos-latest / stable (push) Has been cancelled
Test Suite / windows-latest / stable (push) Has been cancelled
Test Suite / ubuntu / stable / coverage (push) Has been cancelled
2026-01-22 09:06:38 -07:00
30 changed files with 429 additions and 21 deletions
+53 -1
View File
@@ -507,6 +507,56 @@ mod tests {
assert_none!(config.custom_headers); assert_none!(config.custom_headers);
} }
#[test]
#[serial]
fn test_deserialize_optional_env_var_string_vec_is_present() {
unsafe { std::env::set_var("TEST_VAR_DESERIALIZE_STRING_VEC_OPTION", "/path1") };
let expected_monitored_paths = ["/path1", "/path2"];
let yaml_data = r#"
monitored_storage_paths:
- ${TEST_VAR_DESERIALIZE_STRING_VEC_OPTION}
- /path2
"#;
let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap();
assert_some_eq_x!(&config.monitored_storage_paths, &expected_monitored_paths);
unsafe { std::env::remove_var("TEST_VAR_DESERIALIZE_STRING_VEC_OPTION") };
}
#[test]
#[serial]
fn test_deserialize_optional_env_var_string_vec_does_not_overwrite_non_env_value() {
unsafe {
std::env::set_var(
"TEST_VAR_DESERIALIZE_STRING_VEC_OPTION_NO_OVERWRITE",
"/path3",
)
};
let expected_monitored_paths = ["/path1", "/path2"];
let yaml_data = r#"
monitored_storage_paths:
- /path1
- /path2
"#;
let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap();
assert_some_eq_x!(&config.monitored_storage_paths, &expected_monitored_paths);
unsafe { std::env::remove_var("TEST_VAR_DESERIALIZE_STRING_VEC_OPTION_NO_OVERWRITE") };
}
#[test]
fn test_deserialize_optional_env_var_string_vec_empty() {
let yaml_data = r#"
api_token: "test123"
"#;
let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap();
assert_none!(config.monitored_storage_paths);
}
#[test] #[test]
#[serial] #[serial]
fn test_deserialize_optional_u16_env_var_is_present() { fn test_deserialize_optional_u16_env_var_is_present() {
@@ -620,10 +670,11 @@ mod tests {
let api_token = "thisisatest".to_owned(); let api_token = "thisisatest".to_owned();
let api_token_file = "/root/.config/api_token".to_owned(); let api_token_file = "/root/.config/api_token".to_owned();
let ssl_cert_path = "/some/path".to_owned(); let ssl_cert_path = "/some/path".to_owned();
let monitored_storage = vec!["/path1".to_owned(), "/path2".to_owned()];
let mut custom_headers = HeaderMap::new(); let mut custom_headers = HeaderMap::new();
custom_headers.insert("X-Custom-Header", "value".parse().unwrap()); custom_headers.insert("X-Custom-Header", "value".parse().unwrap());
let expected_str = format!( let expected_str = format!(
"ServarrConfig {{ name: Some(\"{name}\"), host: Some(\"{host}\"), port: Some({port}), uri: Some(\"{uri}\"), weight: Some({weight}), api_token: Some(\"***********\"), api_token_file: Some(\"{api_token_file}\"), ssl_cert_path: Some(\"{ssl_cert_path}\"), custom_headers: Some({{\"x-custom-header\": \"value\"}}) }}" "ServarrConfig {{ name: Some(\"{name}\"), host: Some(\"{host}\"), port: Some({port}), uri: Some(\"{uri}\"), weight: Some({weight}), api_token: Some(\"***********\"), api_token_file: Some(\"{api_token_file}\"), ssl_cert_path: Some(\"{ssl_cert_path}\"), custom_headers: Some({{\"x-custom-header\": \"value\"}}), monitored_storage_paths: Some([\"/path1\", \"/path2\"]) }}"
); );
let servarr_config = ServarrConfig { let servarr_config = ServarrConfig {
name: Some(name), name: Some(name),
@@ -635,6 +686,7 @@ mod tests {
api_token_file: Some(api_token_file), api_token_file: Some(api_token_file),
ssl_cert_path: Some(ssl_cert_path), ssl_cert_path: Some(ssl_cert_path),
custom_headers: Some(custom_headers), custom_headers: Some(custom_headers),
monitored_storage_paths: Some(monitored_storage),
}; };
assert_str_eq!(format!("{servarr_config:?}"), expected_str); assert_str_eq!(format!("{servarr_config:?}"), expected_str);
+21
View File
@@ -436,6 +436,8 @@ pub struct ServarrConfig {
serialize_with = "serialize_header_map" serialize_with = "serialize_header_map"
)] )]
pub custom_headers: Option<HeaderMap>, pub custom_headers: Option<HeaderMap>,
#[serde(default, deserialize_with = "deserialize_optional_env_var_string_vec")]
pub monitored_storage_paths: Option<Vec<String>>,
} }
impl ServarrConfig { impl ServarrConfig {
@@ -482,6 +484,7 @@ impl Default for ServarrConfig {
api_token_file: None, api_token_file: None,
ssl_cert_path: None, ssl_cert_path: None,
custom_headers: None, custom_headers: None,
monitored_storage_paths: None,
} }
} }
} }
@@ -548,6 +551,24 @@ where
} }
} }
fn deserialize_optional_env_var_string_vec<'de, D>(
deserializer: D,
) -> Result<Option<Vec<String>>, D::Error>
where
D: serde::Deserializer<'de>,
{
let opt: Option<Vec<String>> = Option::deserialize(deserializer)?;
match opt {
Some(vec) => Ok(Some(
vec
.into_iter()
.map(|it| interpolate_env_vars(&it))
.collect(),
)),
None => Ok(None),
}
}
fn deserialize_u16_env_var<'de, D>(deserializer: D) -> Result<Option<u16>, D::Error> fn deserialize_u16_env_var<'de, D>(deserializer: D) -> Result<Option<u16>, D::Error>
where where
D: serde::Deserializer<'de>, D: serde::Deserializer<'de>,
+13
View File
@@ -2,6 +2,7 @@ use std::sync::Arc;
use anyhow::Result; use anyhow::Result;
use clap::{Subcommand, arg}; use clap::{Subcommand, arg};
use indoc::formatdoc;
use serde_json::json; use serde_json::json;
use tokio::sync::Mutex; use tokio::sync::Mutex;
@@ -59,6 +60,11 @@ pub enum LidarrListCommand {
Artists, Artists,
#[command(about = "List all items in the Lidarr blocklist")] #[command(about = "List all items in the Lidarr blocklist")]
Blocklist, Blocklist,
#[command(about = formatdoc!(
"List disk space details for all provisioned root folders in Lidarr
(returns unfiltered response; i.e. ignores 'monitored_storage_paths' config field)")
)]
DiskSpace,
#[command(about = "List all active downloads in Lidarr")] #[command(about = "List all active downloads in Lidarr")]
Downloads { Downloads {
#[arg(long, help = "How many downloads to fetch", default_value_t = 500)] #[arg(long, help = "How many downloads to fetch", default_value_t = 500)]
@@ -209,6 +215,13 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, LidarrListCommand> for LidarrListCommandH
.await?; .await?;
serde_json::to_string_pretty(&resp)? serde_json::to_string_pretty(&resp)?
} }
LidarrListCommand::DiskSpace => {
let resp = self
.network
.handle_network_event(LidarrEvent::GetDiskSpace.into())
.await?;
serde_json::to_string_pretty(&resp)?
}
LidarrListCommand::Downloads { count } => { LidarrListCommand::Downloads { count } => {
let resp = self let resp = self
.network .network
@@ -28,6 +28,7 @@ mod tests {
#[values( #[values(
"artists", "artists",
"blocklist", "blocklist",
"disk-space",
"indexers", "indexers",
"metadata-profiles", "metadata-profiles",
"quality-profiles", "quality-profiles",
@@ -435,6 +436,7 @@ mod tests {
#[rstest] #[rstest]
#[case(LidarrListCommand::Artists, LidarrEvent::ListArtists)] #[case(LidarrListCommand::Artists, LidarrEvent::ListArtists)]
#[case(LidarrListCommand::Blocklist, LidarrEvent::GetBlocklist)] #[case(LidarrListCommand::Blocklist, LidarrEvent::GetBlocklist)]
#[case(LidarrListCommand::DiskSpace, LidarrEvent::GetDiskSpace)]
#[case(LidarrListCommand::Indexers, LidarrEvent::GetIndexers)] #[case(LidarrListCommand::Indexers, LidarrEvent::GetIndexers)]
#[case(LidarrListCommand::MetadataProfiles, LidarrEvent::GetMetadataProfiles)] #[case(LidarrListCommand::MetadataProfiles, LidarrEvent::GetMetadataProfiles)]
#[case(LidarrListCommand::QualityProfiles, LidarrEvent::GetQualityProfiles)] #[case(LidarrListCommand::QualityProfiles, LidarrEvent::GetQualityProfiles)]
+5 -1
View File
@@ -2,6 +2,7 @@ use std::sync::Arc;
use anyhow::Result; use anyhow::Result;
use clap::{Subcommand, command}; use clap::{Subcommand, command};
use indoc::formatdoc;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use crate::{ use crate::{
@@ -27,7 +28,10 @@ pub enum RadarrListCommand {
#[arg(long, help = "How many downloads to fetch", default_value_t = 500)] #[arg(long, help = "How many downloads to fetch", default_value_t = 500)]
count: u64, count: u64,
}, },
#[command(about = "List disk space details for all provisioned root folders in Radarr")] #[command(about = formatdoc!(
"List disk space details for all provisioned root folders in Radarr
(returns unfiltered response; i.e. ignores 'monitored_storage_paths' config field)")
)]
DiskSpace, DiskSpace,
#[command(about = "Fetch all Radarr history events")] #[command(about = "Fetch all Radarr history events")]
History { History {
+5 -1
View File
@@ -2,6 +2,7 @@ use std::sync::Arc;
use anyhow::Result; use anyhow::Result;
use clap::Subcommand; use clap::Subcommand;
use indoc::formatdoc;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use crate::{ use crate::{
@@ -25,7 +26,10 @@ pub enum SonarrListCommand {
#[arg(long, help = "How many downloads to fetch", default_value_t = 500)] #[arg(long, help = "How many downloads to fetch", default_value_t = 500)]
count: u64, count: u64,
}, },
#[command(about = "List disk space details for all provisioned root folders in Sonarr")] #[command(about = formatdoc!(
"List disk space details for all provisioned root folders in Sonarr
(returns unfiltered response; i.e. ignores 'monitored_storage_paths' config field)")
)]
DiskSpace, DiskSpace,
#[command(about = "List the episodes for the series with the given ID")] #[command(about = "List the episodes for the series with the given ID")]
Episodes { Episodes {
+1
View File
@@ -296,6 +296,7 @@ mod tests {
#[test] #[test]
fn test_lidarr_serdeable_from_disk_spaces() { fn test_lidarr_serdeable_from_disk_spaces() {
let disk_spaces = vec![DiskSpace { let disk_spaces = vec![DiskSpace {
path: Some("/path".to_owned()),
free_space: 1, free_space: 1,
total_space: 1, total_space: 1,
}]; }];
+1
View File
@@ -233,6 +233,7 @@ mod tests {
#[test] #[test]
fn test_radarr_serdeable_from_disk_spaces() { fn test_radarr_serdeable_from_disk_spaces() {
let disk_spaces = vec![DiskSpace { let disk_spaces = vec![DiskSpace {
path: Some("/path".to_owned()),
free_space: 1, free_space: 1,
total_space: 1, total_space: 1,
}]; }];
+1
View File
@@ -83,6 +83,7 @@ pub struct CommandBody {
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct DiskSpace { pub struct DiskSpace {
pub path: Option<String>,
#[serde(deserialize_with = "super::from_i64")] #[serde(deserialize_with = "super::from_i64")]
pub free_space: i64, pub free_space: i64,
#[serde(deserialize_with = "super::from_i64")] #[serde(deserialize_with = "super::from_i64")]
+1
View File
@@ -427,6 +427,7 @@ mod tests {
#[test] #[test]
fn test_sonarr_serdeable_from_disk_spaces() { fn test_sonarr_serdeable_from_disk_spaces() {
let disk_spaces = vec![DiskSpace { let disk_spaces = vec![DiskSpace {
path: Some("/path".to_owned()),
free_space: 1, free_space: 1,
total_space: 1, total_space: 1,
}]; }];
@@ -1,5 +1,6 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::app::{App, ServarrConfig};
use crate::models::HorizontallyScrollableText; use crate::models::HorizontallyScrollableText;
use crate::models::lidarr_models::{LidarrSerdeable, LidarrTask, LidarrTaskName, SystemStatus}; use crate::models::lidarr_models::{LidarrSerdeable, LidarrTask, LidarrTaskName, SystemStatus};
use crate::models::servarr_models::{ use crate::models::servarr_models::{
@@ -11,26 +12,46 @@ mod tests {
use chrono::DateTime; use chrono::DateTime;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use serde_json::json; use serde_json::json;
use std::sync::Arc;
use tokio::sync::Mutex;
#[tokio::test] #[tokio::test]
async fn test_handle_get_diskspace_event() { async fn test_handle_get_diskspace_event() {
let diskspace_json = json!([ let diskspace_json = json!([
{ {
"path": "/path1",
"freeSpace": 1111, "freeSpace": 1111,
"totalSpace": 2222, "totalSpace": 2222,
}, },
{ {
"path": "/path2",
"freeSpace": 3333, "freeSpace": 3333,
"totalSpace": 4444 "totalSpace": 4444
} }
]); ]);
let response: Vec<DiskSpace> = serde_json::from_value(diskspace_json.clone()).unwrap();
let (mock, app, _server) = MockServarrApi::get() let (mock, app, _server) = MockServarrApi::get()
.returns(diskspace_json) .returns(diskspace_json)
.build_for(LidarrEvent::GetDiskSpace) .build_for(LidarrEvent::GetDiskSpace)
.await; .await;
app.lock().await.server_tabs.set_index(2); app.lock().await.server_tabs.set_index(2);
let mut network = test_network(&app); let mut network = test_network(&app);
let filtered_disk_space_vec = vec![DiskSpace {
path: Some("/path1".to_owned()),
free_space: 1111,
total_space: 2222,
}];
let disk_space_vec = vec![
DiskSpace {
path: Some("/path1".to_owned()),
free_space: 1111,
total_space: 2222,
},
DiskSpace {
path: Some("/path2".to_owned()),
free_space: 3333,
total_space: 4444,
},
];
let result = network.handle_lidarr_event(LidarrEvent::GetDiskSpace).await; let result = network.handle_lidarr_event(LidarrEvent::GetDiskSpace).await;
@@ -40,8 +61,71 @@ mod tests {
panic!("Expected DiskSpaces"); panic!("Expected DiskSpaces");
}; };
assert_eq!(disk_spaces, response); assert_eq!(
assert!(!app.lock().await.data.lidarr_data.disk_space_vec.is_empty()); app.lock().await.data.lidarr_data.disk_space_vec,
filtered_disk_space_vec
);
assert_eq!(disk_spaces, disk_space_vec);
}
#[tokio::test]
async fn test_handle_get_lidarr_diskspace_event_populates_data_with_all_storage_when_monitored_storage_paths_is_empty()
{
let (mock, base_app, _server) = MockServarrApi::get()
.returns(json!([
{
"path": "/path1",
"freeSpace": 1111,
"totalSpace": 2222,
},
{
"path": "/path2",
"freeSpace": 3333,
"totalSpace": 4444
}
]))
.build_for(LidarrEvent::GetDiskSpace)
.await;
let mut app = App::test_default();
let servarr_config = ServarrConfig {
monitored_storage_paths: Some(vec![]),
..base_app.lock().await.server_tabs.tabs[2]
.config
.as_ref()
.unwrap()
.clone()
};
app.server_tabs.tabs[2].config = Some(servarr_config);
app.server_tabs.set_index(2);
let app_arc = Arc::new(Mutex::new(app));
let mut network = test_network(&app_arc);
let disk_space_vec = vec![
DiskSpace {
path: Some("/path1".to_owned()),
free_space: 1111,
total_space: 2222,
},
DiskSpace {
path: Some("/path2".to_owned()),
free_space: 3333,
total_space: 4444,
},
];
let LidarrSerdeable::DiskSpaces(disk_space) = network
.handle_lidarr_event(LidarrEvent::GetDiskSpace)
.await
.unwrap()
else {
panic!("Expected DiskSpaces")
};
mock.assert_async().await;
assert_eq!(
app_arc.lock().await.data.lidarr_data.disk_space_vec,
disk_space_vec
);
assert_eq!(disk_space, disk_space_vec);
} }
#[tokio::test] #[tokio::test]
+22 -1
View File
@@ -101,7 +101,28 @@ impl Network<'_, '_> {
self self
.handle_request::<(), Vec<DiskSpace>>(request_props, |disk_space_vec, mut app| { .handle_request::<(), Vec<DiskSpace>>(request_props, |disk_space_vec, mut app| {
app.data.lidarr_data.disk_space_vec = disk_space_vec; if let Some(paths) = app
.server_tabs
.get_active_config()
.as_ref()
.expect("Servarr config is undefined")
.monitored_storage_paths
.as_ref()
&& !paths.is_empty()
{
app.data.lidarr_data.disk_space_vec = disk_space_vec
.into_iter()
.filter(|it| {
if let Some(path) = it.path.as_ref() {
paths.contains(path)
} else {
true
}
})
.collect();
} else {
app.data.lidarr_data.disk_space_vec = disk_space_vec;
}
}) })
.await .await
} }
+1
View File
@@ -862,6 +862,7 @@ pub(in crate::network) mod test_utils {
host, host,
port, port,
api_token: Some("test1234".to_owned()), api_token: Some("test1234".to_owned()),
monitored_storage_paths: Some(vec!["/path1".to_owned()]),
..ServarrConfig::default() ..ServarrConfig::default()
}; };
+22 -1
View File
@@ -27,7 +27,28 @@ impl Network<'_, '_> {
self self
.handle_request::<(), Vec<DiskSpace>>(request_props, |disk_space_vec, mut app| { .handle_request::<(), Vec<DiskSpace>>(request_props, |disk_space_vec, mut app| {
app.data.radarr_data.disk_space_vec = disk_space_vec; if let Some(paths) = app
.server_tabs
.get_active_config()
.as_ref()
.expect("Servarr config is undefined")
.monitored_storage_paths
.as_ref()
&& !paths.is_empty()
{
app.data.radarr_data.disk_space_vec = disk_space_vec
.into_iter()
.filter(|it| {
if let Some(path) = it.path.as_ref() {
paths.contains(path)
} else {
true
}
})
.collect();
} else {
app.data.radarr_data.disk_space_vec = disk_space_vec;
}
}) })
.await .await
} }
@@ -1,5 +1,6 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::app::{App, ServarrConfig};
use crate::models::HorizontallyScrollableText; use crate::models::HorizontallyScrollableText;
use crate::models::radarr_models::{RadarrSerdeable, RadarrTask, RadarrTaskName, SystemStatus}; use crate::models::radarr_models::{RadarrSerdeable, RadarrTask, RadarrTaskName, SystemStatus};
use crate::models::servarr_models::{ use crate::models::servarr_models::{
@@ -11,16 +12,20 @@ mod tests {
use chrono::DateTime; use chrono::DateTime;
use pretty_assertions::{assert_eq, assert_str_eq}; use pretty_assertions::{assert_eq, assert_str_eq};
use serde_json::json; use serde_json::json;
use std::sync::Arc;
use tokio::sync::Mutex;
#[tokio::test] #[tokio::test]
async fn test_handle_get_radarr_diskspace_event() { async fn test_handle_get_radarr_diskspace_event() {
let (mock, app, _server) = MockServarrApi::get() let (mock, app, _server) = MockServarrApi::get()
.returns(json!([ .returns(json!([
{ {
"path": "/path1",
"freeSpace": 1111, "freeSpace": 1111,
"totalSpace": 2222, "totalSpace": 2222,
}, },
{ {
"path": "/path2",
"freeSpace": 3333, "freeSpace": 3333,
"totalSpace": 4444 "totalSpace": 4444
} }
@@ -28,12 +33,19 @@ mod tests {
.build_for(RadarrEvent::GetDiskSpace) .build_for(RadarrEvent::GetDiskSpace)
.await; .await;
let mut network = test_network(&app); let mut network = test_network(&app);
let filtered_disk_space_vec = vec![DiskSpace {
path: Some("/path1".to_owned()),
free_space: 1111,
total_space: 2222,
}];
let disk_space_vec = vec![ let disk_space_vec = vec![
DiskSpace { DiskSpace {
path: Some("/path1".to_owned()),
free_space: 1111, free_space: 1111,
total_space: 2222, total_space: 2222,
}, },
DiskSpace { DiskSpace {
path: Some("/path2".to_owned()),
free_space: 3333, free_space: 3333,
total_space: 4444, total_space: 4444,
}, },
@@ -49,6 +61,65 @@ mod tests {
mock.assert_async().await; mock.assert_async().await;
assert_eq!( assert_eq!(
app.lock().await.data.radarr_data.disk_space_vec, app.lock().await.data.radarr_data.disk_space_vec,
filtered_disk_space_vec
);
assert_eq!(disk_space, disk_space_vec);
}
#[tokio::test]
async fn test_handle_get_radarr_diskspace_event_populates_data_with_all_storage_when_monitored_storage_paths_is_empty()
{
let (mock, base_app, _server) = MockServarrApi::get()
.returns(json!([
{
"path": "/path1",
"freeSpace": 1111,
"totalSpace": 2222,
},
{
"path": "/path2",
"freeSpace": 3333,
"totalSpace": 4444
}
]))
.build_for(RadarrEvent::GetDiskSpace)
.await;
let mut app = App::test_default();
let servarr_config = ServarrConfig {
monitored_storage_paths: Some(vec![]),
..base_app.lock().await.server_tabs.tabs[0]
.config
.as_ref()
.unwrap()
.clone()
};
app.server_tabs.tabs[0].config = Some(servarr_config);
let app_arc = Arc::new(Mutex::new(app));
let mut network = test_network(&app_arc);
let disk_space_vec = vec![
DiskSpace {
path: Some("/path1".to_owned()),
free_space: 1111,
total_space: 2222,
},
DiskSpace {
path: Some("/path2".to_owned()),
free_space: 3333,
total_space: 4444,
},
];
let RadarrSerdeable::DiskSpaces(disk_space) = network
.handle_radarr_event(RadarrEvent::GetDiskSpace)
.await
.unwrap()
else {
panic!("Expected DiskSpaces")
};
mock.assert_async().await;
assert_eq!(
app_arc.lock().await.data.radarr_data.disk_space_vec,
disk_space_vec disk_space_vec
); );
assert_eq!(disk_space, disk_space_vec); assert_eq!(disk_space, disk_space_vec);
+1
View File
@@ -4,6 +4,7 @@ use chrono::DateTime;
pub fn diskspace() -> DiskSpace { pub fn diskspace() -> DiskSpace {
DiskSpace { DiskSpace {
path: Some("/path".to_owned()),
free_space: 6500, free_space: 6500,
total_space: 8675309, total_space: 8675309,
} }
+22 -1
View File
@@ -101,7 +101,28 @@ impl Network<'_, '_> {
self self
.handle_request::<(), Vec<DiskSpace>>(request_props, |disk_space_vec, mut app| { .handle_request::<(), Vec<DiskSpace>>(request_props, |disk_space_vec, mut app| {
app.data.sonarr_data.disk_space_vec = disk_space_vec; if let Some(paths) = app
.server_tabs
.get_active_config()
.as_ref()
.expect("Servarr config is undefined")
.monitored_storage_paths
.as_ref()
&& !paths.is_empty()
{
app.data.sonarr_data.disk_space_vec = disk_space_vec
.into_iter()
.filter(|it| {
if let Some(path) = it.path.as_ref() {
paths.contains(path)
} else {
true
}
})
.collect();
} else {
app.data.sonarr_data.disk_space_vec = disk_space_vec;
}
}) })
.await .await
} }
@@ -1,5 +1,6 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::app::{App, ServarrConfig};
use crate::models::HorizontallyScrollableText; use crate::models::HorizontallyScrollableText;
use crate::models::servarr_models::{ use crate::models::servarr_models::{
DiskSpace, HostConfig, LogResponse, QueueEvent, SecurityConfig, Update, DiskSpace, HostConfig, LogResponse, QueueEvent, SecurityConfig, Update,
@@ -11,6 +12,8 @@ mod tests {
use chrono::DateTime; use chrono::DateTime;
use pretty_assertions::{assert_eq, assert_str_eq}; use pretty_assertions::{assert_eq, assert_str_eq};
use serde_json::json; use serde_json::json;
use std::sync::Arc;
use tokio::sync::Mutex;
#[tokio::test] #[tokio::test]
async fn test_handle_get_sonarr_host_config_event() { async fn test_handle_get_sonarr_host_config_event() {
@@ -113,10 +116,12 @@ mod tests {
let (mock, app, _server) = MockServarrApi::get() let (mock, app, _server) = MockServarrApi::get()
.returns(json!([ .returns(json!([
{ {
"path": "/path1",
"freeSpace": 1111, "freeSpace": 1111,
"totalSpace": 2222, "totalSpace": 2222,
}, },
{ {
"path": "/path2",
"freeSpace": 3333, "freeSpace": 3333,
"totalSpace": 4444 "totalSpace": 4444
} }
@@ -125,12 +130,19 @@ mod tests {
.await; .await;
app.lock().await.server_tabs.next(); app.lock().await.server_tabs.next();
let mut network = test_network(&app); let mut network = test_network(&app);
let filtered_disk_space_vec = vec![DiskSpace {
path: Some("/path1".to_owned()),
free_space: 1111,
total_space: 2222,
}];
let disk_space_vec = vec![ let disk_space_vec = vec![
DiskSpace { DiskSpace {
path: Some("/path1".to_owned()),
free_space: 1111, free_space: 1111,
total_space: 2222, total_space: 2222,
}, },
DiskSpace { DiskSpace {
path: Some("/path2".to_owned()),
free_space: 3333, free_space: 3333,
total_space: 4444, total_space: 4444,
}, },
@@ -146,6 +158,66 @@ mod tests {
mock.assert_async().await; mock.assert_async().await;
assert_eq!( assert_eq!(
app.lock().await.data.sonarr_data.disk_space_vec, app.lock().await.data.sonarr_data.disk_space_vec,
filtered_disk_space_vec
);
assert_eq!(disk_space, disk_space_vec);
}
#[tokio::test]
async fn test_handle_get_sonarr_diskspace_event_populates_data_with_all_storage_when_monitored_storage_paths_is_empty()
{
let (mock, base_app, _server) = MockServarrApi::get()
.returns(json!([
{
"path": "/path1",
"freeSpace": 1111,
"totalSpace": 2222,
},
{
"path": "/path2",
"freeSpace": 3333,
"totalSpace": 4444
}
]))
.build_for(SonarrEvent::GetDiskSpace)
.await;
let mut app = App::test_default();
let servarr_config = ServarrConfig {
monitored_storage_paths: Some(vec![]),
..base_app.lock().await.server_tabs.tabs[1]
.config
.as_ref()
.unwrap()
.clone()
};
app.server_tabs.tabs[1].config = Some(servarr_config);
app.server_tabs.next();
let app_arc = Arc::new(Mutex::new(app));
let mut network = test_network(&app_arc);
let disk_space_vec = vec![
DiskSpace {
path: Some("/path1".to_owned()),
free_space: 1111,
total_space: 2222,
},
DiskSpace {
path: Some("/path2".to_owned()),
free_space: 3333,
total_space: 4444,
},
];
let SonarrSerdeable::DiskSpaces(disk_space) = network
.handle_sonarr_event(SonarrEvent::GetDiskSpace)
.await
.unwrap()
else {
panic!("Expected DiskSpaces")
};
mock.assert_async().await;
assert_eq!(
app_arc.lock().await.data.sonarr_data.disk_space_vec,
disk_space_vec disk_space_vec
); );
assert_eq!(disk_space, disk_space_vec); assert_eq!(disk_space, disk_space_vec);
+6 -1
View File
@@ -148,10 +148,15 @@ fn draw_stats_context(f: &mut Frame<'_>, app: &App<'_>, area: Rect) {
for i in 0..disk_space_vec.len() { for i in 0..disk_space_vec.len() {
let DiskSpace { let DiskSpace {
path,
free_space, free_space,
total_space, total_space,
} = &disk_space_vec[i]; } = &disk_space_vec[i];
let title = format!("Disk {}", i + 1); let title = if let Some(path) = path {
path
} else {
&format!("Disk {}", i + 1)
};
let ratio = if *total_space == 0 { let ratio = if *total_space == 0 {
0f64 0f64
} else { } else {
+6 -1
View File
@@ -141,10 +141,15 @@ fn draw_stats_context(f: &mut Frame<'_>, app: &App<'_>, area: Rect) {
for i in 0..disk_space_vec.len() { for i in 0..disk_space_vec.len() {
let DiskSpace { let DiskSpace {
path,
free_space, free_space,
total_space, total_space,
} = &disk_space_vec[i]; } = &disk_space_vec[i];
let title = format!("Disk {}", i + 1); let title = if let Some(path) = path {
path
} else {
&format!("Disk {}", i + 1)
};
let ratio = if *total_space == 0 { let ratio = if *total_space == 0 {
0f64 0f64
} else { } else {
@@ -9,7 +9,7 @@ expression: output
│Lidarr Version: 1.2.3.4 ││Test download title ││ ⠀⠀⠀⣠⣴⣶⡿⠻⣿⣶⣦⣄⠀⠀⠀ │ │Lidarr Version: 1.2.3.4 ││Test download title ││ ⠀⠀⠀⣠⣴⣶⡿⠻⣿⣶⣦⣄⠀⠀⠀ │
│Uptime: 0d 00:00:44 ││50% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ⠀⢠⣾⠟⠋⠀⠀⢀⣀⠀⠙⠻⣷⡄⠀ │ │Uptime: 0d 00:00:44 ││50% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ⠀⢠⣾⠟⠋⠀⠀⢀⣀⠀⠙⠻⣷⡄⠀ │
│Storage: ││ ││ ⢠⣿⠋⠀⣴⠃⠀⢸⣿⣿⣦⡀⠙⣿⡄ │ │Storage: ││ ││ ⢠⣿⠋⠀⣴⠃⠀⢸⣿⣿⣦⡀⠙⣿⡄ │
Disk 1: 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ││ ⣾⡟⠀⢸⠃⠀⠀⠀⠈⠉⠉⠁⠀⢹⣷ │ /path: 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ││ ⣾⡟⠀⢸⠃⠀⠀⠀⠈⠉⠉⠁⠀⢹⣷ │
│Root Folders: ││ ││ ⢿⣧⠀⠈⠀⠀⠀⠀⠀⠀⢀⡟⠀⣸⡿ │ │Root Folders: ││ ││ ⢿⣧⠀⠈⠀⠀⠀⠀⠀⠀⢀⡟⠀⣸⡿ │
│/nfs: 204800.00 GB free ││ ││ ⠘⣿⣄⠀⠻⣿⣿⡇⠀⢀⠞⠀⣠⣿⠃ │ │/nfs: 204800.00 GB free ││ ││ ⠘⣿⣄⠀⠻⣿⣿⡇⠀⢀⠞⠀⣠⣿⠃ │
│ ││ ││ ⠀⠘⢿⣦⣄⠀⠉⠁⠀⠀⣠⣴⡿⠃⠀ │ │ ││ ││ ⠀⠘⢿⣦⣄⠀⠉⠁⠀⠀⣠⣴⡿⠃⠀ │
@@ -9,7 +9,7 @@ expression: output
│Lidarr Version: 1.2.3.4 ╭ Keybindings ──────────────────────────────────────────────────────────────────────────╮ ││ ⠀⠀⠀⣠⣴⣶⡿⠻⣿⣶⣦⣄⠀⠀⠀ │ │Lidarr Version: 1.2.3.4 ╭ Keybindings ──────────────────────────────────────────────────────────────────────────╮ ││ ⠀⠀⠀⣠⣴⣶⡿⠻⣿⣶⣦⣄⠀⠀⠀ │
│Uptime: 0d 00:00:44 │ Key Alt Key Description │━━━━━━━━━━━━━━━━━││ ⠀⢠⣾⠟⠋⠀⠀⢀⣀⠀⠙⠻⣷⡄⠀ │ │Uptime: 0d 00:00:44 │ Key Alt Key Description │━━━━━━━━━━━━━━━━━││ ⠀⢠⣾⠟⠋⠀⠀⢀⣀⠀⠙⠻⣷⡄⠀ │
│Storage: │=> a add │ ││ ⢠⣿⠋⠀⣴⠃⠀⢸⣿⣿⣦⡀⠙⣿⡄ │ │Storage: │=> a add │ ││ ⢠⣿⠋⠀⣴⠃⠀⢸⣿⣿⣦⡀⠙⣿⡄ │
Disk 1: 100% ━━━━━━━━━━━━━━━━━━━━━━│ e edit │ ││ ⣾⡟⠀⢸⠃⠀⠀⠀⠈⠉⠉⠁⠀⢹⣷ │ /path: 100% ━━━━━━━━━━━━━━━━━━━━━━│ e edit │ ││ ⣾⡟⠀⢸⠃⠀⠀⠀⠈⠉⠉⠁⠀⢹⣷ │
│Root Folders: │ m toggle monitoring │ ││ ⢿⣧⠀⠈⠀⠀⠀⠀⠀⠀⢀⡟⠀⣸⡿ │ │Root Folders: │ m toggle monitoring │ ││ ⢿⣧⠀⠈⠀⠀⠀⠀⠀⠀⢀⡟⠀⣸⡿ │
│/nfs: 204800.00 GB free │ o sort │ ││ ⠘⣿⣄⠀⠻⣿⣿⡇⠀⢀⠞⠀⣠⣿⠃ │ │/nfs: 204800.00 GB free │ o sort │ ││ ⠘⣿⣄⠀⠻⣿⣿⡇⠀⢀⠞⠀⣠⣿⠃ │
│ │ del delete │ ││ ⠀⠘⢿⣦⣄⠀⠉⠁⠀⠀⣠⣴⡿⠃⠀ │ │ │ del delete │ ││ ⠀⠘⢿⣦⣄⠀⠉⠁⠀⠀⣠⣴⡿⠃⠀ │
@@ -12,7 +12,7 @@ expression: output
│Lidarr Version: 1.2.3.4 ││Test download title ││ ⠀⠀⠀⣠⣴⣶⡿⠻⣿⣶⣦⣄⠀⠀⠀ │ │Lidarr Version: 1.2.3.4 ││Test download title ││ ⠀⠀⠀⣠⣴⣶⡿⠻⣿⣶⣦⣄⠀⠀⠀ │
│Uptime: 0d 00:00:44 ││50% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ⠀⢠⣾⠟⠋⠀⠀⢀⣀⠀⠙⠻⣷⡄⠀ │ │Uptime: 0d 00:00:44 ││50% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ⠀⢠⣾⠟⠋⠀⠀⢀⣀⠀⠙⠻⣷⡄⠀ │
│Storage: ││ ││ ⢠⣿⠋⠀⣴⠃⠀⢸⣿⣿⣦⡀⠙⣿⡄ │ │Storage: ││ ││ ⢠⣿⠋⠀⣴⠃⠀⢸⣿⣿⣦⡀⠙⣿⡄ │
Disk 1: 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ││ ⣾⡟⠀⢸⠃⠀⠀⠀⠈⠉⠉⠁⠀⢹⣷ │ /path: 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ││ ⣾⡟⠀⢸⠃⠀⠀⠀⠈⠉⠉⠁⠀⢹⣷ │
│Root Folders: ││ ││ ⢿⣧⠀⠈⠀⠀⠀⠀⠀⠀⢀⡟⠀⣸⡿ │ │Root Folders: ││ ││ ⢿⣧⠀⠈⠀⠀⠀⠀⠀⠀⢀⡟⠀⣸⡿ │
│/nfs: 204800.00 GB free ││ ││ ⠘⣿⣄⠀⠻⣿⣿⡇⠀⢀⠞⠀⣠⣿⠃ │ │/nfs: 204800.00 GB free ││ ││ ⠘⣿⣄⠀⠻⣿⣿⡇⠀⢀⠞⠀⣠⣿⠃ │
│ ││ ││ ⠀⠘⢿⣦⣄⠀⠉⠁⠀⠀⣠⣴⡿⠃⠀ │ │ ││ ││ ⠀⠘⢿⣦⣄⠀⠉⠁⠀⠀⣠⣴⡿⠃⠀ │
@@ -9,7 +9,7 @@ expression: output
│Radarr Version: 1.2.3.4 ││Test Download Title ││ ⠀⣠⣶⢶⣶⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀ │ │Radarr Version: 1.2.3.4 ││Test Download Title ││ ⠀⣠⣶⢶⣶⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀ │
│Uptime: 0d 00:00:44 ││50% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ⠀⣿⡇⠀⠈⠙⠻⢿⣶⣤⡀⠀⠀⠀⠀ │ │Uptime: 0d 00:00:44 ││50% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ⠀⣿⡇⠀⠈⠙⠻⢿⣶⣤⡀⠀⠀⠀⠀ │
│Storage: ││ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⠈⠙⠻⢷⣦⡄⠀ │ │Storage: ││ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⠈⠙⠻⢷⣦⡄⠀ │
Disk 1: 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢉⠻⠀ │ /path: 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢉⠻⠀ │
│Root Folders: ││ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⢀⣠⣴⣾⠿⠀⠀ │ │Root Folders: ││ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⢀⣠⣴⣾⠿⠀⠀ │
│/nfs: 204800.00 GB free ││ ││ ⠀⢿⡇⠀⠀⣀⣤⣶⡿⠛⠉⠀⠀⠀⠀ │ │/nfs: 204800.00 GB free ││ ││ ⠀⢿⡇⠀⠀⣀⣤⣶⡿⠛⠉⠀⠀⠀⠀ │
│ ││ ││ ⠀⠀⠰⠶⡿⠟⠋⠁⠀⠀⠀⠀⠀⠀⠀ │ │ ││ ││ ⠀⠀⠰⠶⡿⠟⠋⠁⠀⠀⠀⠀⠀⠀⠀ │
@@ -9,7 +9,7 @@ expression: output
│Radarr Version: 1.2.3.4 ╭ Keybindings ──────────────────────────────────────────────────────────────────────────╮ ││ ⠀⣠⣶⢶⣶⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀ │ │Radarr Version: 1.2.3.4 ╭ Keybindings ──────────────────────────────────────────────────────────────────────────╮ ││ ⠀⣠⣶⢶⣶⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀ │
│Uptime: 0d 00:00:44 │ Key Alt Key Description │━━━━━━━━━━━━━━━━━││ ⠀⣿⡇⠀⠈⠙⠻⢿⣶⣤⡀⠀⠀⠀⠀ │ │Uptime: 0d 00:00:44 │ Key Alt Key Description │━━━━━━━━━━━━━━━━━││ ⠀⣿⡇⠀⠈⠙⠻⢿⣶⣤⡀⠀⠀⠀⠀ │
│Storage: │=> a add │ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⠈⠙⠻⢷⣦⡄⠀ │ │Storage: │=> a add │ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⠈⠙⠻⢷⣦⡄⠀ │
Disk 1: 100% ━━━━━━━━━━━━━━━━━━━━━━│ e edit │ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢉⠻⠀ │ /path: 100% ━━━━━━━━━━━━━━━━━━━━━━│ e edit │ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢉⠻⠀ │
│Root Folders: │ m toggle monitoring │ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⢀⣠⣴⣾⠿⠀⠀ │ │Root Folders: │ m toggle monitoring │ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⢀⣠⣴⣾⠿⠀⠀ │
│/nfs: 204800.00 GB free │ o sort │ ││ ⠀⢿⡇⠀⠀⣀⣤⣶⡿⠛⠉⠀⠀⠀⠀ │ │/nfs: 204800.00 GB free │ o sort │ ││ ⠀⢿⡇⠀⠀⣀⣤⣶⡿⠛⠉⠀⠀⠀⠀ │
│ │ del delete │ ││ ⠀⠀⠰⠶⡿⠟⠋⠁⠀⠀⠀⠀⠀⠀⠀ │ │ │ del delete │ ││ ⠀⠀⠰⠶⡿⠟⠋⠁⠀⠀⠀⠀⠀⠀⠀ │
@@ -12,7 +12,7 @@ expression: output
│Radarr Version: 1.2.3.4 ││Test Download Title ││ ⠀⣠⣶⢶⣶⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀ │ │Radarr Version: 1.2.3.4 ││Test Download Title ││ ⠀⣠⣶⢶⣶⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀ │
│Uptime: 0d 00:00:44 ││50% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ⠀⣿⡇⠀⠈⠙⠻⢿⣶⣤⡀⠀⠀⠀⠀ │ │Uptime: 0d 00:00:44 ││50% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ⠀⣿⡇⠀⠈⠙⠻⢿⣶⣤⡀⠀⠀⠀⠀ │
│Storage: ││ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⠈⠙⠻⢷⣦⡄⠀ │ │Storage: ││ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⠈⠙⠻⢷⣦⡄⠀ │
Disk 1: 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢉⠻⠀ │ /path: 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢉⠻⠀ │
│Root Folders: ││ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⢀⣠⣴⣾⠿⠀⠀ │ │Root Folders: ││ ││ ⠀⣿⡇⠀⠀⠀⠀⠀⢀⣠⣴⣾⠿⠀⠀ │
│/nfs: 204800.00 GB free ││ ││ ⠀⢿⡇⠀⠀⣀⣤⣶⡿⠛⠉⠀⠀⠀⠀ │ │/nfs: 204800.00 GB free ││ ││ ⠀⢿⡇⠀⠀⣀⣤⣶⡿⠛⠉⠀⠀⠀⠀ │
│ ││ ││ ⠀⠀⠰⠶⡿⠟⠋⠁⠀⠀⠀⠀⠀⠀⠀ │ │ ││ ││ ⠀⠀⠰⠶⡿⠟⠋⠁⠀⠀⠀⠀⠀⠀⠀ │
@@ -9,7 +9,7 @@ expression: output
│Sonarr Version: 1.2.3.4 ││Test Download Title ││ ⠀⠀⠀⣠⣴⣶⣿⣿⣿⣿⣶⣦⣄⠀⠀⠀ │ │Sonarr Version: 1.2.3.4 ││Test Download Title ││ ⠀⠀⠀⣠⣴⣶⣿⣿⣿⣿⣶⣦⣄⠀⠀⠀ │
│Uptime: 0d 00:00:44 ││50% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ⠀⣠⡀⠈⠻⣿⣿⣿⣿⣿⣿⠟⠁⢀⣀⠀ │ │Uptime: 0d 00:00:44 ││50% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ⠀⣠⡀⠈⠻⣿⣿⣿⣿⣿⣿⠟⠁⢀⣀⠀ │
│Storage: ││ ││ ⢰⣿⣿⣦⠐⠄⠉⠉⠉⠉⠠⠂⣰⣿⣿⡆ │ │Storage: ││ ││ ⢰⣿⣿⣦⠐⠄⠉⠉⠉⠉⠠⠂⣰⣿⣿⡆ │
Disk 1: 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ││ ⣿⣿⣿⣿⡆⠀⣴⣿⣿⣦⠀⢰⣿⣿⣿⣿ │ /path: 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ││ ⣿⣿⣿⣿⡆⠀⣴⣿⣿⣦⠀⢰⣿⣿⣿⣿ │
│Root Folders: ││ ││ ⣿⣿⣿⣿⡇⠀⠻⣿⣿⠟⠀⠸⣿⣿⣿⣿ │ │Root Folders: ││ ││ ⣿⣿⣿⣿⡇⠀⠻⣿⣿⠟⠀⠸⣿⣿⣿⣿ │
│/nfs: 204800.00 GB free ││ ││ ⠸⣿⣿⠟⠠⠂⠀⢀⡀⠀⠐⠄⠻⣿⣿⠇ │ │/nfs: 204800.00 GB free ││ ││ ⠸⣿⣿⠟⠠⠂⠀⢀⡀⠀⠐⠄⠻⣿⣿⠇ │
│ ││ ││ ⠀⠙⠁⢀⣴⣾⣿⣿⣿⣿⣷⣦⡀⠈⠋⠀ │ │ ││ ││ ⠀⠙⠁⢀⣴⣾⣿⣿⣿⣿⣷⣦⡀⠈⠋⠀ │
@@ -9,7 +9,7 @@ expression: output
│Sonarr Version: 1.2.3.4 ╭ Keybindings ──────────────────────────────────────────────────────────────────────────╮ ││ ⠀⠀⠀⣠⣴⣶⣿⣿⣿⣿⣶⣦⣄⠀⠀⠀ │ │Sonarr Version: 1.2.3.4 ╭ Keybindings ──────────────────────────────────────────────────────────────────────────╮ ││ ⠀⠀⠀⣠⣴⣶⣿⣿⣿⣿⣶⣦⣄⠀⠀⠀ │
│Uptime: 0d 00:00:44 │ Key Alt Key Description │━━━━━━━━━━━━━━━━━││ ⠀⣠⡀⠈⠻⣿⣿⣿⣿⣿⣿⠟⠁⢀⣀⠀ │ │Uptime: 0d 00:00:44 │ Key Alt Key Description │━━━━━━━━━━━━━━━━━││ ⠀⣠⡀⠈⠻⣿⣿⣿⣿⣿⣿⠟⠁⢀⣀⠀ │
│Storage: │=> a add │ ││ ⢰⣿⣿⣦⠐⠄⠉⠉⠉⠉⠠⠂⣰⣿⣿⡆ │ │Storage: │=> a add │ ││ ⢰⣿⣿⣦⠐⠄⠉⠉⠉⠉⠠⠂⣰⣿⣿⡆ │
Disk 1: 100% ━━━━━━━━━━━━━━━━━━━━━━│ e edit │ ││ ⣿⣿⣿⣿⡆⠀⣴⣿⣿⣦⠀⢰⣿⣿⣿⣿ │ /path: 100% ━━━━━━━━━━━━━━━━━━━━━━│ e edit │ ││ ⣿⣿⣿⣿⡆⠀⣴⣿⣿⣦⠀⢰⣿⣿⣿⣿ │
│Root Folders: │ m toggle monitoring │ ││ ⣿⣿⣿⣿⡇⠀⠻⣿⣿⠟⠀⠸⣿⣿⣿⣿ │ │Root Folders: │ m toggle monitoring │ ││ ⣿⣿⣿⣿⡇⠀⠻⣿⣿⠟⠀⠸⣿⣿⣿⣿ │
│/nfs: 204800.00 GB free │ o sort │ ││ ⠸⣿⣿⠟⠠⠂⠀⢀⡀⠀⠐⠄⠻⣿⣿⠇ │ │/nfs: 204800.00 GB free │ o sort │ ││ ⠸⣿⣿⠟⠠⠂⠀⢀⡀⠀⠐⠄⠻⣿⣿⠇ │
│ │ del delete │ ││ ⠀⠙⠁⢀⣴⣾⣿⣿⣿⣿⣷⣦⡀⠈⠋⠀ │ │ │ del delete │ ││ ⠀⠙⠁⢀⣴⣾⣿⣿⣿⣿⣷⣦⡀⠈⠋⠀ │
@@ -12,7 +12,7 @@ expression: output
│Sonarr Version: 1.2.3.4 ││Test Download Title ││ ⠀⠀⠀⣠⣴⣶⣿⣿⣿⣿⣶⣦⣄⠀⠀⠀ │ │Sonarr Version: 1.2.3.4 ││Test Download Title ││ ⠀⠀⠀⣠⣴⣶⣿⣿⣿⣿⣶⣦⣄⠀⠀⠀ │
│Uptime: 0d 00:00:44 ││50% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ⠀⣠⡀⠈⠻⣿⣿⣿⣿⣿⣿⠟⠁⢀⣀⠀ │ │Uptime: 0d 00:00:44 ││50% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ⠀⣠⡀⠈⠻⣿⣿⣿⣿⣿⣿⠟⠁⢀⣀⠀ │
│Storage: ││ ││ ⢰⣿⣿⣦⠐⠄⠉⠉⠉⠉⠠⠂⣰⣿⣿⡆ │ │Storage: ││ ││ ⢰⣿⣿⣦⠐⠄⠉⠉⠉⠉⠠⠂⣰⣿⣿⡆ │
Disk 1: 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ││ ⣿⣿⣿⣿⡆⠀⣴⣿⣿⣦⠀⢰⣿⣿⣿⣿ │ /path: 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ││ ⣿⣿⣿⣿⡆⠀⣴⣿⣿⣦⠀⢰⣿⣿⣿⣿ │
│Root Folders: ││ ││ ⣿⣿⣿⣿⡇⠀⠻⣿⣿⠟⠀⠸⣿⣿⣿⣿ │ │Root Folders: ││ ││ ⣿⣿⣿⣿⡇⠀⠻⣿⣿⠟⠀⠸⣿⣿⣿⣿ │
│/nfs: 204800.00 GB free ││ ││ ⠸⣿⣿⠟⠠⠂⠀⢀⡀⠀⠐⠄⠻⣿⣿⠇ │ │/nfs: 204800.00 GB free ││ ││ ⠸⣿⣿⠟⠠⠂⠀⢀⡀⠀⠐⠄⠻⣿⣿⠇ │
│ ││ ││ ⠀⠙⠁⢀⣴⣾⣿⣿⣿⣿⣷⣦⡀⠈⠋⠀ │ │ ││ ││ ⠀⠙⠁⢀⣴⣾⣿⣿⣿⣿⣷⣦⡀⠈⠋⠀ │
+7 -1
View File
@@ -149,10 +149,16 @@ fn draw_stats_context(f: &mut Frame<'_>, app: &App<'_>, area: Rect) {
for i in 0..disk_space_vec.len() { for i in 0..disk_space_vec.len() {
let DiskSpace { let DiskSpace {
path,
free_space, free_space,
total_space, total_space,
..
} = &disk_space_vec[i]; } = &disk_space_vec[i];
let title = format!("Disk {}", i + 1); let title = if let Some(path) = path {
path
} else {
&format!("Disk {}", i + 1)
};
let ratio = if *total_space == 0 { let ratio = if *total_space == 0 {
0f64 0f64
} else { } else {