Add tags, export/import, and changelog features
- Tag editor in detail view with add/remove pill chips - Tag filter chips in library view for filtering by tag - Shared backup module for app list export/import (JSON v2) - CLI export/import refactored to use shared module - GUI export/import via file picker dialogs in hamburger menu - GitHub release history enrichment for catalog apps - Changelog preview in updates view with expandable rows - DB migration v19 for catalog release_history column
This commit is contained in:
@@ -265,6 +265,72 @@ pub fn enrich_app_release_info(
|
||||
Ok(remaining)
|
||||
}
|
||||
|
||||
/// A GitHub release with body text for changelog display.
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
struct GitHubRelease {
|
||||
tag_name: String,
|
||||
published_at: Option<String>,
|
||||
body: Option<String>,
|
||||
}
|
||||
|
||||
/// Fetch up to 10 recent releases for a repo.
|
||||
fn fetch_recent_releases(owner: &str, repo: &str, token: &str) -> Result<(Vec<GitHubRelease>, u32), String> {
|
||||
let url = format!("https://api.github.com/repos/{}/{}/releases?per_page=10", owner, repo);
|
||||
let (body, remaining) = github_get(&url, token)?;
|
||||
let releases: Vec<GitHubRelease> = serde_json::from_str(&body)
|
||||
.map_err(|e| format!("Parse error: {}", e))?;
|
||||
Ok((releases, remaining))
|
||||
}
|
||||
|
||||
/// Enrich a catalog app with release history (version, date, description for last 10 releases).
|
||||
/// Only populates if the existing release_history is empty.
|
||||
pub fn enrich_app_release_history(
|
||||
db: &Database,
|
||||
app_id: i64,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
token: &str,
|
||||
) -> Result<u32, String> {
|
||||
// Check if release_history is already populated (from AppStream or prior enrichment)
|
||||
if let Ok(Some(app)) = db.get_catalog_app(app_id) {
|
||||
if app.release_history.as_ref().is_some_and(|h| !h.is_empty()) {
|
||||
return Ok(u32::MAX); // already has data, skip
|
||||
}
|
||||
}
|
||||
|
||||
let (releases, remaining) = fetch_recent_releases(owner, repo, token)?;
|
||||
if releases.is_empty() {
|
||||
return Ok(remaining);
|
||||
}
|
||||
|
||||
// Convert to the same JSON format used by AppStream: [{version, date, description}]
|
||||
let history: Vec<serde_json::Value> = releases.iter().map(|r| {
|
||||
let version = r.tag_name.strip_prefix('v')
|
||||
.unwrap_or(&r.tag_name)
|
||||
.to_string();
|
||||
let date = r.published_at.as_deref()
|
||||
.and_then(|d| d.split('T').next())
|
||||
.unwrap_or("");
|
||||
let mut obj = serde_json::json!({
|
||||
"version": version,
|
||||
"date": date,
|
||||
});
|
||||
if let Some(ref body) = r.body {
|
||||
if !body.is_empty() {
|
||||
obj["description"] = serde_json::Value::String(body.clone());
|
||||
}
|
||||
}
|
||||
obj
|
||||
}).collect();
|
||||
|
||||
let json = serde_json::to_string(&history)
|
||||
.map_err(|e| format!("JSON error: {}", e))?;
|
||||
db.update_catalog_app_release_history(app_id, &json)
|
||||
.map_err(|e| format!("DB error: {}", e))?;
|
||||
|
||||
Ok(remaining)
|
||||
}
|
||||
|
||||
/// Fetch and store the README for a catalog app.
|
||||
pub fn enrich_app_readme(
|
||||
db: &Database,
|
||||
@@ -310,6 +376,9 @@ pub fn background_enrich_batch(
|
||||
Ok(remaining) => {
|
||||
enriched += 1;
|
||||
|
||||
// Also fetch release history (changelog data)
|
||||
let _ = enrich_app_release_history(db, app.id, owner, repo, token);
|
||||
|
||||
// Report progress
|
||||
if let Ok((done, total)) = db.catalog_enrichment_progress() {
|
||||
on_progress(done, total);
|
||||
|
||||
Reference in New Issue
Block a user