ralph/notification/
config.rs1#[derive(Debug, Clone, Default)]
18pub struct NotificationOverrides {
19 pub notify_on_complete: Option<bool>,
21 pub notify_on_fail: Option<bool>,
23 pub notify_sound: Option<bool>,
25}
26
27#[derive(Debug, Clone, Default)]
29pub struct NotificationConfig {
30 pub enabled: bool,
32 pub notify_on_complete: bool,
34 pub notify_on_fail: bool,
36 pub notify_on_loop_complete: bool,
38 pub suppress_when_active: bool,
40 pub sound_enabled: bool,
42 pub sound_path: Option<String>,
45 pub timeout_ms: u32,
47}
48
49impl NotificationConfig {
50 pub fn new() -> Self {
52 Self {
53 enabled: true,
54 notify_on_complete: true,
55 notify_on_fail: true,
56 notify_on_loop_complete: true,
57 suppress_when_active: true,
58 sound_enabled: false,
59 sound_path: None,
60 timeout_ms: 8000,
61 }
62 }
63
64 pub fn should_suppress(&self, ui_active: bool) -> bool {
66 if !self.enabled {
67 return true;
68 }
69 ui_active && self.suppress_when_active
70 }
71}
72
73pub fn build_notification_config(
77 config: &crate::contracts::NotificationConfig,
78 overrides: &NotificationOverrides,
79) -> NotificationConfig {
80 let notify_on_complete = overrides
81 .notify_on_complete
82 .or(config.notify_on_complete)
83 .unwrap_or(true);
84 let notify_on_fail = overrides
85 .notify_on_fail
86 .or(config.notify_on_fail)
87 .unwrap_or(true);
88 let notify_on_loop_complete = config.notify_on_loop_complete.unwrap_or(true);
89
90 NotificationConfig {
91 enabled: notify_on_complete || notify_on_fail || notify_on_loop_complete,
92 notify_on_complete,
93 notify_on_fail,
94 notify_on_loop_complete,
95 suppress_when_active: config.suppress_when_active.unwrap_or(true),
96 sound_enabled: overrides
97 .notify_sound
98 .or(config.sound_enabled)
99 .unwrap_or(false),
100 sound_path: config.sound_path.clone(),
101 timeout_ms: config.timeout_ms.unwrap_or(8000),
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn build_notification_config_uses_defaults() {
111 let config = crate::contracts::NotificationConfig::default();
112 let overrides = NotificationOverrides::default();
113 let result = build_notification_config(&config, &overrides);
114
115 assert!(result.enabled);
116 assert!(result.notify_on_complete);
117 assert!(result.notify_on_fail);
118 assert!(result.notify_on_loop_complete);
119 assert!(result.suppress_when_active);
120 assert!(!result.sound_enabled);
121 assert!(result.sound_path.is_none());
122 assert_eq!(result.timeout_ms, 8000);
123 }
124
125 #[test]
126 fn build_notification_config_overrides_take_precedence() {
127 let config = crate::contracts::NotificationConfig {
128 notify_on_complete: Some(false),
129 notify_on_fail: Some(false),
130 sound_enabled: Some(false),
131 ..Default::default()
132 };
133 let overrides = NotificationOverrides {
134 notify_on_complete: Some(true),
135 notify_on_fail: Some(true),
136 notify_sound: Some(true),
137 };
138 let result = build_notification_config(&config, &overrides);
139
140 assert!(result.notify_on_complete);
141 assert!(result.notify_on_fail);
142 assert!(result.sound_enabled);
143 }
144
145 #[test]
146 fn build_notification_config_config_used_when_no_override() {
147 let config = crate::contracts::NotificationConfig {
148 notify_on_complete: Some(false),
149 notify_on_fail: Some(true),
150 suppress_when_active: Some(false),
151 timeout_ms: Some(5000),
152 sound_path: Some("/path/to/sound.wav".to_string()),
153 ..Default::default()
154 };
155 let overrides = NotificationOverrides::default();
156 let result = build_notification_config(&config, &overrides);
157
158 assert!(!result.notify_on_complete);
159 assert!(result.notify_on_fail);
160 assert!(!result.suppress_when_active);
161 assert_eq!(result.timeout_ms, 5000);
162 assert_eq!(result.sound_path, Some("/path/to/sound.wav".to_string()));
163 }
164
165 #[test]
166 fn build_notification_config_enabled_computed_correctly() {
167 let config = crate::contracts::NotificationConfig {
168 notify_on_complete: Some(false),
169 notify_on_fail: Some(false),
170 notify_on_loop_complete: Some(false),
171 ..Default::default()
172 };
173 let overrides = NotificationOverrides::default();
174 let result = build_notification_config(&config, &overrides);
175 assert!(!result.enabled);
176
177 let config = crate::contracts::NotificationConfig {
178 notify_on_complete: Some(true),
179 notify_on_fail: Some(false),
180 notify_on_loop_complete: Some(false),
181 ..Default::default()
182 };
183 let result = build_notification_config(&config, &overrides);
184 assert!(result.enabled);
185 }
186}