Skip to content

Commit 03f8204

Browse files
committed
refactor: sanitize job stats upon completion and enhance UI with job deletion support and tab filtering logic
1 parent df331a9 commit 03f8204

8 files changed

Lines changed: 267 additions & 299 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
77
## Unreleased
88

99
### Added
10-
- **Language**: Added Ukrainian language support. (Thanks to @maksam07!)
11-
- **CI/CD Validation**: Added a multi-OS GitHub Actions workflow (`ci.yml`) to automatically validate lints, formatting, and compilation checks across Linux, Windows, and macOS on push and pull request triggers.
10+
- **Language**: Added Ukrainian language support. (Thanks to @maksam07!) PR #230
11+
- **CI/CD Validation**: Added a multi-OS GitHub Actions workflow (`ci.yml`) to automatically validate lints, formatting, and compilation checks across Linux, Windows, and macOS on push and pull request triggers. Rust code validating all linux, windows and macos platforms, frontend code validating is only linux platform.
12+
- **PowerShell**: Added PowerShell 7+ (pwsh) support for mount plugin installer. If pwsh is not available on Windows, default to Windows PowerShell (powershell.exe). #229
1213

1314
### Changed
1415
-
1516

1617
### Fixed
17-
-
18+
- Detached dialog and other dialog fixes. #228
1819

1920
## [v0.2.7] - 2026-06-13
2021

src-tauri/src/rclone/state/job.rs

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,19 @@ impl JobCache {
9191
}
9292

9393
pub async fn update_job_stats(&self, jobid: u64, stats: Value) -> Result<(), String> {
94-
self.update_job(jobid, |j| j.stats = Some(stats), None)
95-
.await
96-
.map(|_| ())
94+
self.update_job(
95+
jobid,
96+
|j| {
97+
let mut stats = stats;
98+
if j.status.is_finished() {
99+
sanitize_finished_stats(&mut stats);
100+
}
101+
j.stats = Some(stats);
102+
},
103+
None,
104+
)
105+
.await
106+
.map(|_| ())
97107
}
98108

99109
pub async fn complete_job(
@@ -114,6 +124,9 @@ impl JobCache {
114124
};
115125
j.error = error;
116126
j.end_time = Some(chrono::Utc::now());
127+
if let Some(stats) = j.stats.as_mut() {
128+
sanitize_finished_stats(stats);
129+
}
117130
}
118131
},
119132
app,
@@ -128,6 +141,9 @@ impl JobCache {
128141
if !j.status.is_finished() {
129142
j.status = JobStatus::Stopped;
130143
j.end_time = Some(chrono::Utc::now());
144+
if let Some(stats) = j.stats.as_mut() {
145+
sanitize_finished_stats(stats);
146+
}
131147
}
132148
},
133149
app,
@@ -232,6 +248,14 @@ impl JobCache {
232248
}
233249
}
234250

251+
fn sanitize_finished_stats(stats: &mut Value) {
252+
if let Some(obj) = stats.as_object_mut() {
253+
obj.insert("transferring".to_string(), serde_json::json!([]));
254+
obj.insert("speed".to_string(), serde_json::json!(0.0));
255+
obj.insert("eta".to_string(), Value::Null);
256+
}
257+
}
258+
235259
impl Default for JobCache {
236260
fn default() -> Self {
237261
Self::new()
@@ -317,4 +341,56 @@ mod tests {
317341
assert_eq!(job2.status, JobStatus::Completed);
318342
assert!(job2.error.is_none());
319343
}
344+
345+
#[tokio::test]
346+
async fn test_job_stats_sanitization_on_finish() {
347+
let cache = JobCache::new();
348+
let jobid = 1;
349+
cache
350+
.add_job(mock_job(jobid, "gdrive:", JobType::Sync, None), None)
351+
.await;
352+
353+
// Populate running stats
354+
let active_stats = serde_json::json!({
355+
"bytes": 100,
356+
"totalBytes": 1000,
357+
"speed": 50.0,
358+
"eta": 18,
359+
"transferring": [
360+
{
361+
"name": "file1.txt",
362+
"size": 500,
363+
"bytes": 50,
364+
"speed": 10.0,
365+
"eta": 45
366+
}
367+
]
368+
});
369+
370+
cache
371+
.update_job_stats(jobid, active_stats.clone())
372+
.await
373+
.unwrap();
374+
let job = cache.get_job(jobid).await.unwrap();
375+
let stats_val = job.stats.unwrap();
376+
assert_eq!(stats_val["transferring"].as_array().unwrap().len(), 1);
377+
assert_eq!(stats_val["speed"].as_f64().unwrap(), 50.0);
378+
assert_eq!(stats_val["eta"].as_u64().unwrap(), 18);
379+
380+
// Stop the job and check if stats are sanitized
381+
cache.stop_job(jobid, None).await.unwrap();
382+
let job = cache.get_job(jobid).await.unwrap();
383+
let stats_val = job.stats.unwrap();
384+
assert_eq!(stats_val["transferring"].as_array().unwrap().len(), 0);
385+
assert_eq!(stats_val["speed"].as_f64().unwrap(), 0.0);
386+
assert!(stats_val["eta"].is_null());
387+
388+
// Attempt to update stats on stopped job, it should remain sanitized
389+
cache.update_job_stats(jobid, active_stats).await.unwrap();
390+
let job = cache.get_job(jobid).await.unwrap();
391+
let stats_val = job.stats.unwrap();
392+
assert_eq!(stats_val["transferring"].as_array().unwrap().len(), 0);
393+
assert_eq!(stats_val["speed"].as_f64().unwrap(), 0.0);
394+
assert!(stats_val["eta"].is_null());
395+
}
320396
}

0 commit comments

Comments
 (0)