Merge branch 'develop' into custom-themes

# Conflicts:
#	Cargo.toml
This commit is contained in:
2025-03-06 15:35:05 -07:00
20 changed files with 258 additions and 308 deletions
Generated
+12 -2
View File
@@ -622,6 +622,15 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "enum_display_style_derive"
version = "0.1.0"
dependencies = [
"darling",
"quote",
"syn 2.0.99",
]
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.2" version = "1.0.2"
@@ -1366,6 +1375,7 @@ dependencies = [
"derive_setters", "derive_setters",
"deunicode", "deunicode",
"dirs-next", "dirs-next",
"enum_display_style_derive",
"human-panic", "human-panic",
"indicatif", "indicatif",
"indoc", "indoc",
@@ -1764,9 +1774,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.93" version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
+2 -1
View File
@@ -14,7 +14,7 @@ rust-version = "1.82.0"
exclude = [".github", "CONTRIBUTING.md", "*.log", "tags"] exclude = [".github", "CONTRIBUTING.md", "*.log", "tags"]
[workspace] [workspace]
members = ["proc_macros/validate_theme_derive"] members = ["proc_macros/enum_display_style_derive", "proc_macros/validate_theme_derive"]
[dependencies] [dependencies]
anyhow = "1.0.68" anyhow = "1.0.68"
@@ -64,6 +64,7 @@ paste = "1.0.15"
openssl = { version = "0.10.70", features = ["vendored"] } openssl = { version = "0.10.70", features = ["vendored"] }
veil = "0.2.0" veil = "0.2.0"
validate_theme_derive = { path = "proc_macros/validate_theme_derive" } validate_theme_derive = { path = "proc_macros/validate_theme_derive" }
enum_display_style_derive = { path = "proc_macros/enum_display_style_derive" }
[dev-dependencies] [dev-dependencies]
assert_cmd = "2.0.16" assert_cmd = "2.0.16"
+1 -1
View File
@@ -8,7 +8,7 @@ default: run
.PHONY: test test-cov build run lint lint-fix fmt analyze sonar release delete-tag .PHONY: test test-cov build run lint lint-fix fmt analyze sonar release delete-tag
test: test:
@cargo test @cargo test --all
## Run all tests with coverage - `cargo install cargo-tarpaulin` ## Run all tests with coverage - `cargo install cargo-tarpaulin`
test-cov: test-cov:
@@ -0,0 +1,12 @@
[package]
name = "enum_display_style_derive"
version = "0.1.0"
edition = "2024"
[lib]
proc-macro = true
[dependencies]
quote = "1.0.39"
syn = "2.0.99"
darling = "0.20.10"
@@ -0,0 +1,77 @@
mod macro_models;
use crate::macro_models::DisplayStyleArgs;
use darling::FromVariant;
use quote::quote;
use syn::{Data, DeriveInput, parse_macro_input};
/// Derive macro for the EnumDisplayStyle trait.
///
/// # Example
///
/// Using default values for the display style:
///
/// ```
/// use enum_display_style_derive::EnumDisplayStyle;
///
/// #[derive(EnumDisplayStyle)]
/// enum Weekend {
/// Saturday,
/// Sunday,
/// }
///
/// assert_eq!(Weekend::Saturday.to_display_str(), "Saturday");
/// assert_eq!(Weekend::Sunday.to_display_str(), "Sunday");
///
/// ```
///
/// Using custom values for the display style:
///
/// ```
/// use enum_display_style_derive::EnumDisplayStyle;
///
/// #[derive(EnumDisplayStyle)]
/// enum MonitorStatus {
/// #[display_style(name = "Monitor Transactions")]
/// Active,
/// #[display_style(name = "Don't Monitor Transactions")]
/// None,
/// }
///
/// assert_eq!(MonitorStatus::Active.to_display_str(), "Monitor Transactions");
/// assert_eq!(MonitorStatus::None.to_display_str(), "Don't Monitor Transactions");
/// ```
#[proc_macro_derive(EnumDisplayStyle, attributes(display_style))]
pub fn enum_display_style_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let enum_name = &input.ident;
let mut match_arms = Vec::new();
if let Data::Enum(data_enum) = &input.data {
let variants = &data_enum.variants;
for variant in variants {
let variant_ident = &variant.ident;
let variant_display_name = DisplayStyleArgs::from_variant(variant)
.unwrap()
.name
.unwrap_or_else(|| variant_ident.to_string());
match_arms.push(quote! {
#enum_name::#variant_ident => #variant_display_name,
});
}
}
quote! {
impl<'a> #enum_name {
pub fn to_display_str(self) -> &'a str {
match self {
#(#match_arms)*
}
}
}
}
.into()
}
@@ -0,0 +1,7 @@
use darling::FromVariant;
#[derive(Debug, FromVariant)]
#[darling(attributes(display_style))]
pub struct DisplayStyleArgs {
pub name: Option<String>,
}
+15 -4
View File
@@ -42,10 +42,6 @@ pub enum Serdeable {
Sonarr(SonarrSerdeable), Sonarr(SonarrSerdeable),
} }
pub trait EnumDisplayStyle<'a> {
fn to_display_str(self) -> &'a str;
}
pub trait Scrollable { pub trait Scrollable {
fn scroll_down(&mut self); fn scroll_down(&mut self);
fn scroll_up(&mut self); fn scroll_up(&mut self);
@@ -445,6 +441,21 @@ pub fn strip_non_search_characters(input: &str) -> String {
#[macro_export] #[macro_export]
macro_rules! serde_enum_from { macro_rules! serde_enum_from {
($enum_name:ident { $($variant:ident($ty:ty),)* }) => { ($enum_name:ident { $($variant:ident($ty:ty),)* }) => {
#[derive(Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, Debug)]
#[serde(untagged)]
#[allow(clippy::large_enum_variant)]
pub enum $enum_name {
$(
$variant($ty),
)*
}
impl From<()> for $enum_name {
fn from(_: ()) -> Self {
$enum_name::Value(serde_json::json!({}))
}
}
$( $(
impl From<$ty> for $enum_name { impl From<$ty> for $enum_name {
fn from(value: $ty) -> Self { fn from(value: $ty) -> Self {
+26 -88
View File
@@ -1,19 +1,19 @@
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use crate::{models::HorizontallyScrollableText, serde_enum_from};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use clap::ValueEnum; use clap::ValueEnum;
use derivative::Derivative; use derivative::Derivative;
use enum_display_style_derive::EnumDisplayStyle;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::{json, Number, Value}; use serde_json::{Number, Value};
use strum_macros::EnumIter; use strum_macros::{Display, EnumIter};
use crate::{models::HorizontallyScrollableText, serde_enum_from};
use super::servarr_models::{ use super::servarr_models::{
DiskSpace, HostConfig, Indexer, Language, LogResponse, QualityProfile, QualityWrapper, DiskSpace, HostConfig, Indexer, Language, LogResponse, QualityProfile, QualityWrapper,
QueueEvent, RootFolder, SecurityConfig, Tag, Update, QueueEvent, RootFolder, SecurityConfig, Tag, Update,
}; };
use super::{EnumDisplayStyle, Serdeable}; use super::Serdeable;
#[cfg(test)] #[cfg(test)]
#[path = "radarr_models_tests.rs"] #[path = "radarr_models_tests.rs"]
@@ -258,69 +258,44 @@ pub struct MediaInfo {
} }
#[derive( #[derive(
Serialize, Deserialize, Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter, ValueEnum, Serialize,
Deserialize,
Default,
PartialEq,
Eq,
Clone,
Copy,
Debug,
EnumIter,
ValueEnum,
Display,
EnumDisplayStyle,
)] )]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
#[strum(serialize_all = "camelCase")]
pub enum MinimumAvailability { pub enum MinimumAvailability {
#[default] #[default]
Announced, Announced,
#[display_style(name = "In Cinemas")]
InCinemas, InCinemas,
Released, Released,
#[display_style(name = "TBA")]
Tba, Tba,
} }
impl Display for MinimumAvailability { #[derive(
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter, ValueEnum, Display, EnumDisplayStyle,
let minimum_availability = match self { )]
MinimumAvailability::Tba => "tba", #[strum(serialize_all = "camelCase")]
MinimumAvailability::Announced => "announced",
MinimumAvailability::InCinemas => "inCinemas",
MinimumAvailability::Released => "released",
};
write!(f, "{minimum_availability}")
}
}
impl<'a> EnumDisplayStyle<'a> for MinimumAvailability {
fn to_display_str(self) -> &'a str {
match self {
MinimumAvailability::Tba => "TBA",
MinimumAvailability::Announced => "Announced",
MinimumAvailability::InCinemas => "In Cinemas",
MinimumAvailability::Released => "Released",
}
}
}
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter, ValueEnum)]
pub enum MovieMonitor { pub enum MovieMonitor {
#[default] #[default]
#[display_style(name = "Movie only")]
MovieOnly, MovieOnly,
#[display_style(name = "Movie and Collection")]
MovieAndCollection, MovieAndCollection,
None, None,
} }
impl Display for MovieMonitor {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let monitor = match self {
MovieMonitor::MovieOnly => "movieOnly",
MovieMonitor::MovieAndCollection => "movieAndCollection",
MovieMonitor::None => "none",
};
write!(f, "{monitor}")
}
}
impl<'a> EnumDisplayStyle<'a> for MovieMonitor {
fn to_display_str(self) -> &'a str {
match self {
MovieMonitor::MovieOnly => "Movie only",
MovieMonitor::MovieAndCollection => "Movie and Collection",
MovieMonitor::None => "None",
}
}
}
#[derive(Derivative, Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)] #[derive(Derivative, Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Movie { pub struct Movie {
@@ -475,49 +450,12 @@ impl Display for RadarrTaskName {
} }
} }
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
#[serde(untagged)]
#[allow(clippy::large_enum_variant)]
pub enum RadarrSerdeable {
Value(Value),
Tag(Tag),
BlocklistResponse(BlocklistResponse),
Collections(Vec<Collection>),
Credits(Vec<Credit>),
DiskSpaces(Vec<DiskSpace>),
DownloadsResponse(DownloadsResponse),
HostConfig(HostConfig),
Indexers(Vec<Indexer>),
IndexerSettings(IndexerSettings),
LogResponse(LogResponse),
Movie(Movie),
MovieHistoryItems(Vec<MovieHistoryItem>),
Movies(Vec<Movie>),
QualityProfiles(Vec<QualityProfile>),
QueueEvents(Vec<QueueEvent>),
Releases(Vec<RadarrRelease>),
RootFolders(Vec<RootFolder>),
SecurityConfig(SecurityConfig),
SystemStatus(SystemStatus),
Tags(Vec<Tag>),
Tasks(Vec<RadarrTask>),
Updates(Vec<Update>),
AddMovieSearchResults(Vec<AddMovieSearchResult>),
IndexerTestResults(Vec<IndexerTestResult>),
}
impl From<RadarrSerdeable> for Serdeable { impl From<RadarrSerdeable> for Serdeable {
fn from(value: RadarrSerdeable) -> Serdeable { fn from(value: RadarrSerdeable) -> Serdeable {
Serdeable::Radarr(value) Serdeable::Radarr(value)
} }
} }
impl From<()> for RadarrSerdeable {
fn from(_: ()) -> Self {
RadarrSerdeable::Value(json!({}))
}
}
serde_enum_from!( serde_enum_from!(
RadarrSerdeable { RadarrSerdeable {
Value(Value), Value(Value),
+1 -1
View File
@@ -11,7 +11,7 @@ mod tests {
RadarrSerdeable, RadarrTask, RadarrTaskName, SystemStatus, Tag, Update, RadarrSerdeable, RadarrTask, RadarrTaskName, SystemStatus, Tag, Update,
}, },
servarr_models::{HostConfig, Log, LogResponse, QueueEvent, RootFolder, SecurityConfig}, servarr_models::{HostConfig, Log, LogResponse, QueueEvent, RootFolder, SecurityConfig},
EnumDisplayStyle, Serdeable, Serdeable,
}; };
#[test] #[test]
+81 -202
View File
@@ -1,13 +1,14 @@
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use crate::serde_enum_from;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use clap::ValueEnum; use clap::ValueEnum;
use derivative::Derivative; use derivative::Derivative;
use enum_display_style_derive::EnumDisplayStyle;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::{json, Number, Value}; use serde_json::{Number, Value};
use strum::EnumIter; use strum::EnumIter;
use strum_macros::Display;
use crate::serde_enum_from;
use super::{ use super::{
radarr_models::IndexerTestResult, radarr_models::IndexerTestResult,
@@ -15,7 +16,7 @@ use super::{
DiskSpace, HostConfig, Indexer, Language, LogResponse, QualityProfile, QualityWrapper, DiskSpace, HostConfig, Indexer, Language, LogResponse, QualityProfile, QualityWrapper,
QueueEvent, RootFolder, SecurityConfig, Tag, Update, QueueEvent, RootFolder, SecurityConfig, Tag, Update,
}, },
EnumDisplayStyle, HorizontallyScrollableText, Serdeable, HorizontallyScrollableText, Serdeable,
}; };
#[cfg(test)] #[cfg(test)]
@@ -125,8 +126,21 @@ pub struct DownloadRecord {
impl Eq for DownloadRecord {} impl Eq for DownloadRecord {}
#[derive(Serialize, Deserialize, Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter)] #[derive(
Serialize,
Deserialize,
Default,
PartialEq,
Eq,
Clone,
Copy,
Debug,
EnumIter,
Display,
EnumDisplayStyle,
)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
#[strum(serialize_all = "camelCase")]
pub enum DownloadStatus { pub enum DownloadStatus {
#[default] #[default]
Unknown, Unknown,
@@ -137,45 +151,11 @@ pub enum DownloadStatus {
Failed, Failed,
Warning, Warning,
Delay, Delay,
#[display_style(name = "Download Client Unavailable")]
DownloadClientUnavailable, DownloadClientUnavailable,
Fallback, Fallback,
} }
impl Display for DownloadStatus {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let download_status = match self {
DownloadStatus::Unknown => "unknown",
DownloadStatus::Queued => "queued",
DownloadStatus::Paused => "paused",
DownloadStatus::Downloading => "downloading",
DownloadStatus::Completed => "completed",
DownloadStatus::Failed => "failed",
DownloadStatus::Warning => "warning",
DownloadStatus::Delay => "delay",
DownloadStatus::DownloadClientUnavailable => "downloadClientUnavailable",
DownloadStatus::Fallback => "fallback",
};
write!(f, "{download_status}")
}
}
impl<'a> EnumDisplayStyle<'a> for DownloadStatus {
fn to_display_str(self) -> &'a str {
match self {
DownloadStatus::Unknown => "Unknown",
DownloadStatus::Queued => "Queued",
DownloadStatus::Paused => "Paused",
DownloadStatus::Downloading => "Downloading",
DownloadStatus::Completed => "Completed",
DownloadStatus::Failed => "Failed",
DownloadStatus::Warning => "Warning",
DownloadStatus::Delay => "Delay",
DownloadStatus::DownloadClientUnavailable => "Download Client Unavailable",
DownloadStatus::Fallback => "Fallback",
}
}
}
#[derive(Default, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] #[derive(Default, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct DownloadsResponse { pub struct DownloadsResponse {
@@ -363,74 +343,66 @@ pub struct Series {
} }
#[derive( #[derive(
Serialize, Deserialize, Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter, ValueEnum, Serialize,
Deserialize,
Default,
PartialEq,
Eq,
Clone,
Copy,
Debug,
EnumIter,
ValueEnum,
Display,
EnumDisplayStyle,
)] )]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
#[strum(serialize_all = "camelCase")]
pub enum SeriesMonitor { pub enum SeriesMonitor {
#[default] #[default]
#[display_style(name = "All Episodes")]
All, All,
Unknown, Unknown,
#[display_style(name = "Future Episodes")]
Future, Future,
#[display_style(name = "Missing Episodes")]
Missing, Missing,
#[display_style(name = "Existing Episodes")]
Existing, Existing,
#[display_style(name = "Only First Season")]
FirstSeason, FirstSeason,
#[display_style(name = "Only Last Season")]
LastSeason, LastSeason,
#[display_style(name = "Only Latest Season")]
LatestSeason, LatestSeason,
#[display_style(name = "Pilot Episode")]
Pilot, Pilot,
#[display_style(name = "Recent Episodes")]
Recent, Recent,
#[display_style(name = "Only Specials")]
MonitorSpecials, MonitorSpecials,
#[display_style(name = "Not Specials")]
UnmonitorSpecials, UnmonitorSpecials,
None, None,
Skip, Skip,
} }
impl Display for SeriesMonitor {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let series_monitor = match self {
SeriesMonitor::Unknown => "unknown",
SeriesMonitor::All => "all",
SeriesMonitor::Future => "future",
SeriesMonitor::Missing => "missing",
SeriesMonitor::Existing => "existing",
SeriesMonitor::FirstSeason => "firstSeason",
SeriesMonitor::LastSeason => "lastSeason",
SeriesMonitor::LatestSeason => "latestSeason",
SeriesMonitor::Pilot => "pilot",
SeriesMonitor::Recent => "recent",
SeriesMonitor::MonitorSpecials => "monitorSpecials",
SeriesMonitor::UnmonitorSpecials => "unmonitorSpecials",
SeriesMonitor::None => "none",
SeriesMonitor::Skip => "skip",
};
write!(f, "{series_monitor}")
}
}
impl<'a> EnumDisplayStyle<'a> for SeriesMonitor {
fn to_display_str(self) -> &'a str {
match self {
SeriesMonitor::Unknown => "Unknown",
SeriesMonitor::All => "All Episodes",
SeriesMonitor::Future => "Future Episodes",
SeriesMonitor::Missing => "Missing Episodes",
SeriesMonitor::Existing => "Existing Episodes",
SeriesMonitor::FirstSeason => "Only First Season",
SeriesMonitor::LastSeason => "Only Last Season",
SeriesMonitor::LatestSeason => "Only Latest Season",
SeriesMonitor::Pilot => "Pilot Episode",
SeriesMonitor::Recent => "Recent Episodes",
SeriesMonitor::MonitorSpecials => "Only Specials",
SeriesMonitor::UnmonitorSpecials => "Not Specials",
SeriesMonitor::None => "None",
SeriesMonitor::Skip => "Skip",
}
}
}
#[derive( #[derive(
Serialize, Deserialize, Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter, ValueEnum, Serialize,
Deserialize,
Default,
PartialEq,
Eq,
Clone,
Copy,
Debug,
EnumIter,
ValueEnum,
Display,
EnumDisplayStyle,
)] )]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
#[strum(serialize_all = "camelCase")]
pub enum SeriesType { pub enum SeriesType {
#[default] #[default]
Standard, Standard,
@@ -438,27 +410,6 @@ pub enum SeriesType {
Anime, Anime,
} }
impl Display for SeriesType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let series_type = match self {
SeriesType::Standard => "standard",
SeriesType::Daily => "daily",
SeriesType::Anime => "anime",
};
write!(f, "{series_type}")
}
}
impl<'a> EnumDisplayStyle<'a> for SeriesType {
fn to_display_str(self) -> &'a str {
match self {
SeriesType::Standard => "Standard",
SeriesType::Daily => "Daily",
SeriesType::Anime => "Anime",
}
}
}
#[derive(Derivative, Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[derive(Derivative, Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct SeriesStatistics { pub struct SeriesStatistics {
@@ -478,8 +429,21 @@ pub struct SeriesStatistics {
impl Eq for SeriesStatistics {} impl Eq for SeriesStatistics {}
#[derive(Serialize, Deserialize, Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter)] #[derive(
Serialize,
Deserialize,
Default,
PartialEq,
Eq,
Clone,
Copy,
Debug,
EnumIter,
Display,
EnumDisplayStyle,
)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
#[strum(serialize_all = "camelCase")]
pub enum SeriesStatus { pub enum SeriesStatus {
#[default] #[default]
Continuing, Continuing,
@@ -488,29 +452,6 @@ pub enum SeriesStatus {
Deleted, Deleted,
} }
impl Display for SeriesStatus {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let series_status = match self {
SeriesStatus::Continuing => "continuing",
SeriesStatus::Ended => "ended",
SeriesStatus::Upcoming => "upcoming",
SeriesStatus::Deleted => "deleted",
};
write!(f, "{series_status}")
}
}
impl<'a> EnumDisplayStyle<'a> for SeriesStatus {
fn to_display_str(self) -> &'a str {
match self {
SeriesStatus::Continuing => "Continuing",
SeriesStatus::Ended => "Ended",
SeriesStatus::Upcoming => "Upcoming",
SeriesStatus::Deleted => "Deleted",
}
}
}
#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)] #[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct SonarrHistoryWrapper { pub struct SonarrHistoryWrapper {
@@ -537,51 +478,29 @@ pub struct SonarrHistoryData {
pub relative_path: Option<String>, pub relative_path: Option<String>,
} }
#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)] #[derive(
Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq, Display, EnumDisplayStyle,
)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
#[strum(serialize_all = "camelCase")]
pub enum SonarrHistoryEventType { pub enum SonarrHistoryEventType {
#[default] #[default]
Unknown, Unknown,
Grabbed, Grabbed,
#[display_style(name = "Series Folder Imported")]
SeriesFolderImported, SeriesFolderImported,
#[display_style(name = "Download Folder Imported")]
DownloadFolderImported, DownloadFolderImported,
#[display_style(name = "Download Failed")]
DownloadFailed, DownloadFailed,
#[display_style(name = "Episode File Deleted")]
EpisodeFileDeleted, EpisodeFileDeleted,
#[display_style(name = "Episode File Renamed")]
EpisodeFileRenamed, EpisodeFileRenamed,
#[display_style(name = "Download Ignored")]
DownloadIgnored, DownloadIgnored,
} }
impl Display for SonarrHistoryEventType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let event_type = match self {
SonarrHistoryEventType::Unknown => "unknown",
SonarrHistoryEventType::Grabbed => "grabbed",
SonarrHistoryEventType::SeriesFolderImported => "seriesFolderImported",
SonarrHistoryEventType::DownloadFolderImported => "downloadFolderImported",
SonarrHistoryEventType::DownloadFailed => "downloadFailed",
SonarrHistoryEventType::EpisodeFileDeleted => "episodeFileDeleted",
SonarrHistoryEventType::EpisodeFileRenamed => "episodeFileRenamed",
SonarrHistoryEventType::DownloadIgnored => "downloadIgnored",
};
write!(f, "{event_type}")
}
}
impl<'a> EnumDisplayStyle<'a> for SonarrHistoryEventType {
fn to_display_str(self) -> &'a str {
match self {
SonarrHistoryEventType::Unknown => "Unknown",
SonarrHistoryEventType::Grabbed => "Grabbed",
SonarrHistoryEventType::SeriesFolderImported => "Series Folder Imported",
SonarrHistoryEventType::DownloadFolderImported => "Download Folder Imported",
SonarrHistoryEventType::DownloadFailed => "Download Failed",
SonarrHistoryEventType::EpisodeFileDeleted => "Episode File Deleted",
SonarrHistoryEventType::EpisodeFileRenamed => "Episode File Renamed",
SonarrHistoryEventType::DownloadIgnored => "Download Ignored",
}
}
}
#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)] #[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct SonarrHistoryItem { pub struct SonarrHistoryItem {
@@ -681,52 +600,12 @@ impl Display for SonarrTaskName {
} }
} }
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
#[serde(untagged)]
#[allow(clippy::large_enum_variant)]
pub enum SonarrSerdeable {
AddSeriesSearchResults(Vec<AddSeriesSearchResult>),
BlocklistResponse(BlocklistResponse),
DownloadsResponse(DownloadsResponse),
DiskSpaces(Vec<DiskSpace>),
Episode(Episode),
Episodes(Vec<Episode>),
EpisodeFiles(Vec<EpisodeFile>),
HostConfig(HostConfig),
IndexerSettings(IndexerSettings),
Indexers(Vec<Indexer>),
IndexerTestResults(Vec<IndexerTestResult>),
LanguageProfiles(Vec<Language>),
LogResponse(LogResponse),
QualityProfiles(Vec<QualityProfile>),
QueueEvents(Vec<QueueEvent>),
Releases(Vec<SonarrRelease>),
RootFolders(Vec<RootFolder>),
SecurityConfig(SecurityConfig),
SeriesVec(Vec<Series>),
Series(Series),
SonarrHistoryItems(Vec<SonarrHistoryItem>),
SonarrHistoryWrapper(SonarrHistoryWrapper),
SystemStatus(SystemStatus),
Tag(Tag),
Tags(Vec<Tag>),
Tasks(Vec<SonarrTask>),
Updates(Vec<Update>),
Value(Value),
}
impl From<SonarrSerdeable> for Serdeable { impl From<SonarrSerdeable> for Serdeable {
fn from(value: SonarrSerdeable) -> Serdeable { fn from(value: SonarrSerdeable) -> Serdeable {
Serdeable::Sonarr(value) Serdeable::Sonarr(value)
} }
} }
impl From<()> for SonarrSerdeable {
fn from(_: ()) -> Self {
SonarrSerdeable::Value(json!({}))
}
}
serde_enum_from!( serde_enum_from!(
SonarrSerdeable { SonarrSerdeable {
AddSeriesSearchResults(Vec<AddSeriesSearchResult>), AddSeriesSearchResults(Vec<AddSeriesSearchResult>),
+1 -1
View File
@@ -15,7 +15,7 @@ mod tests {
SeriesStatus, SeriesType, SonarrHistoryEventType, SonarrHistoryItem, SonarrRelease, SeriesStatus, SeriesType, SonarrHistoryEventType, SonarrHistoryItem, SonarrRelease,
SonarrSerdeable, SonarrTask, SonarrTaskName, SystemStatus, SonarrSerdeable, SonarrTask, SonarrTaskName, SystemStatus,
}, },
EnumDisplayStyle, Serdeable, Serdeable,
}; };
#[test] #[test]
@@ -11,7 +11,7 @@ use crate::models::radarr_models::CollectionMovie;
use crate::models::servarr_data::radarr::radarr_data::{ use crate::models::servarr_data::radarr::radarr_data::{
ActiveRadarrBlock, COLLECTION_DETAILS_BLOCKS, ActiveRadarrBlock, COLLECTION_DETAILS_BLOCKS,
}; };
use crate::models::{EnumDisplayStyle, Route}; use crate::models::Route;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{ use crate::ui::utils::{
borderless_block, get_width_from_percentage, layout_block_top_border_with_title, title_block, borderless_block, get_width_from_percentage, layout_block_top_border_with_title, title_block,
@@ -10,7 +10,7 @@ use crate::models::servarr_data::radarr::modals::EditCollectionModal;
use crate::models::servarr_data::radarr::radarr_data::{ use crate::models::servarr_data::radarr::radarr_data::{
ActiveRadarrBlock, COLLECTION_DETAILS_BLOCKS, EDIT_COLLECTION_BLOCKS, ActiveRadarrBlock, COLLECTION_DETAILS_BLOCKS, EDIT_COLLECTION_BLOCKS,
}; };
use crate::models::{EnumDisplayStyle, Route}; use crate::models::Route;
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::radarr_ui::collections::collection_details_ui::CollectionDetailsUi; use crate::ui::radarr_ui::collections::collection_details_ui::CollectionDetailsUi;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
+1 -1
View File
@@ -12,7 +12,7 @@ use crate::app::radarr::radarr_context_clues::ADD_MOVIE_SEARCH_RESULTS_CONTEXT_C
use crate::models::radarr_models::AddMovieSearchResult; use crate::models::radarr_models::AddMovieSearchResult;
use crate::models::servarr_data::radarr::modals::AddMovieModal; use crate::models::servarr_data::radarr::modals::AddMovieModal;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, ADD_MOVIE_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, ADD_MOVIE_BLOCKS};
use crate::models::{EnumDisplayStyle, Route}; use crate::models::Route;
use crate::ui::radarr_ui::collections::CollectionsUi; use crate::ui::radarr_ui::collections::CollectionsUi;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{ use crate::ui::utils::{
+1 -1
View File
@@ -12,7 +12,7 @@ use crate::models::servarr_data::radarr::modals::EditMovieModal;
use crate::models::servarr_data::radarr::radarr_data::{ use crate::models::servarr_data::radarr::radarr_data::{
ActiveRadarrBlock, EDIT_MOVIE_BLOCKS, MOVIE_DETAILS_BLOCKS, ActiveRadarrBlock, EDIT_MOVIE_BLOCKS, MOVIE_DETAILS_BLOCKS,
}; };
use crate::models::{EnumDisplayStyle, Route}; use crate::models::Route;
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::radarr_ui::library::movie_details_ui::MovieDetailsUi; use crate::ui::radarr_ui::library::movie_details_ui::MovieDetailsUi;
+1 -1
View File
@@ -12,7 +12,7 @@ use crate::app::sonarr::sonarr_context_clues::ADD_SERIES_SEARCH_RESULTS_CONTEXT_
use crate::models::servarr_data::sonarr::modals::AddSeriesModal; use crate::models::servarr_data::sonarr::modals::AddSeriesModal;
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, ADD_SERIES_BLOCKS}; use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, ADD_SERIES_BLOCKS};
use crate::models::sonarr_models::AddSeriesSearchResult; use crate::models::sonarr_models::AddSeriesSearchResult;
use crate::models::{EnumDisplayStyle, Route}; use crate::models::Route;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{ use crate::ui::utils::{
borderless_block, get_width_from_percentage, layout_block, layout_paragraph_borderless, borderless_block, get_width_from_percentage, layout_block, layout_paragraph_borderless,
+1 -1
View File
@@ -12,7 +12,7 @@ use crate::models::servarr_data::sonarr::modals::EditSeriesModal;
use crate::models::servarr_data::sonarr::sonarr_data::{ use crate::models::servarr_data::sonarr::sonarr_data::{
ActiveSonarrBlock, EDIT_SERIES_BLOCKS, SERIES_DETAILS_BLOCKS, ActiveSonarrBlock, EDIT_SERIES_BLOCKS, SERIES_DETAILS_BLOCKS,
}; };
use crate::models::{EnumDisplayStyle, Route}; use crate::models::Route;
use crate::render_selectable_input_box; use crate::render_selectable_input_box;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
+1 -1
View File
@@ -17,7 +17,7 @@ use crate::{
models::{ models::{
servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, LIBRARY_BLOCKS}, servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, LIBRARY_BLOCKS},
sonarr_models::{Series, SeriesStatus}, sonarr_models::{Series, SeriesStatus},
EnumDisplayStyle, Route, Route,
}, },
ui::{ ui::{
styles::ManagarrStyle, styles::ManagarrStyle,
@@ -12,7 +12,7 @@ use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SERIES
use crate::models::sonarr_models::{ use crate::models::sonarr_models::{
Season, SeasonStatistics, SonarrHistoryEventType, SonarrHistoryItem, Season, SeasonStatistics, SonarrHistoryEventType, SonarrHistoryItem,
}; };
use crate::models::{EnumDisplayStyle, Route}; use crate::models::Route;
use crate::ui::sonarr_ui::library::episode_details_ui::EpisodeDetailsUi; use crate::ui::sonarr_ui::library::episode_details_ui::EpisodeDetailsUi;
use crate::ui::sonarr_ui::library::season_details_ui::SeasonDetailsUi; use crate::ui::sonarr_ui::library::season_details_ui::SeasonDetailsUi;
use crate::ui::sonarr_ui::sonarr_ui_utils::{ use crate::ui::sonarr_ui::sonarr_ui_utils::{
+15
View File
@@ -0,0 +1,15 @@
use enum_display_style_derive::EnumDisplayStyle;
use pretty_assertions::assert_str_eq;
#[test]
fn test_derive_enum_display_style() {
assert_str_eq!(TestEnum::Test.to_display_str(), "Testing 123");
assert_str_eq!(TestEnum::Ignored.to_display_str(), "Ignored");
}
#[derive(EnumDisplayStyle)]
pub enum TestEnum {
#[display_style(name = "Testing 123")]
Test,
Ignored,
}