mirror of
https://github.com/modrinth/code.git
synced 2026-08-28 10:34:53 +00:00
feat: content management changes (#6104)
* feat: change modpack updating flow * fix: pending install state loss * fix: mods.vue perf problems * chore: todo doc * draft: try preload/fix suspense * fix: lint
This commit is contained in:
@@ -3,13 +3,12 @@
|
||||
//! ## Data Flow
|
||||
//!
|
||||
//! 1. Frontend calls `get_content_items(profile_path)`
|
||||
//! 2. Backend fetches all installed files via `Profile::get_projects()`
|
||||
//! 3. If profile is linked to a modpack:
|
||||
//! 2. If profile is linked to a modpack:
|
||||
//! - Fetch modpack file hashes from cache (populated during installation)
|
||||
//! - Fallback: re-download .mrpack if cache miss (cleared/expired)
|
||||
//! - Filter out files that belong to the modpack
|
||||
//! 4. For remaining files, fetch project/version/owner metadata in parallel
|
||||
//! 5. Return sorted `ContentItem` list
|
||||
//! - Filter out files that belong to the modpack before update lookup
|
||||
//! 3. For remaining files, fetch project/version/owner metadata in parallel
|
||||
//! 4. Return sorted `ContentItem` list
|
||||
//!
|
||||
//! ## Caching
|
||||
//!
|
||||
@@ -226,12 +225,8 @@ pub async fn get_linked_modpack_info(
|
||||
};
|
||||
|
||||
// Check for updates
|
||||
let (has_update, update_version_id, update_version) = check_modpack_update(
|
||||
profile,
|
||||
&linked_data.version_id,
|
||||
&version,
|
||||
all_versions,
|
||||
);
|
||||
let (has_update, update_version_id, update_version) =
|
||||
check_modpack_update(&linked_data.version_id, &version, all_versions);
|
||||
|
||||
Ok(Some(LinkedModpackInfo {
|
||||
project,
|
||||
@@ -243,10 +238,9 @@ pub async fn get_linked_modpack_info(
|
||||
}))
|
||||
}
|
||||
|
||||
/// Check if a newer compatible version exists for the linked modpack.
|
||||
/// Check if a newer version exists for the linked modpack.
|
||||
/// Returns (has_update, update_version_id, update_version).
|
||||
fn check_modpack_update(
|
||||
profile: &Profile,
|
||||
installed_version_id: &str,
|
||||
installed_version: &Version,
|
||||
all_versions: Option<Vec<Version>>,
|
||||
@@ -255,44 +249,19 @@ fn check_modpack_update(
|
||||
return (false, None, None);
|
||||
};
|
||||
|
||||
// Get the loader as a string for comparison
|
||||
let loader_str = profile.loader.as_str().to_lowercase();
|
||||
let game_version = &profile.game_version;
|
||||
|
||||
// Filter to compatible versions
|
||||
let mut compatible_versions: Vec<&Version> = versions
|
||||
let mut newer_versions: Vec<&Version> = versions
|
||||
.iter()
|
||||
.filter(|v| {
|
||||
// Must support the profile's game version
|
||||
let supports_game = v.game_versions.contains(game_version);
|
||||
|
||||
// Must support the profile's loader
|
||||
// The v2 API replaces "mrpack" with actual loaders from mrpack_loaders,
|
||||
// but if mrpack_loaders is missing, loaders may be just ["mrpack"].
|
||||
// In that case we can't filter by loader, so accept the version.
|
||||
let real_loaders: Vec<_> = v
|
||||
.loaders
|
||||
.iter()
|
||||
.filter(|l| l.to_lowercase() != "mrpack")
|
||||
.collect();
|
||||
let supports_loader = real_loaders.is_empty()
|
||||
|| real_loaders.iter().any(|l| l.to_lowercase() == loader_str);
|
||||
|
||||
supports_game && supports_loader
|
||||
v.id != installed_version_id
|
||||
&& v.date_published > installed_version.date_published
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Sort by date_published descending (newest first)
|
||||
compatible_versions.sort_by_key(|b| std::cmp::Reverse(b.date_published));
|
||||
newer_versions.sort_by_key(|b| std::cmp::Reverse(b.date_published));
|
||||
|
||||
// Find the newest compatible version
|
||||
if let Some(newest) = compatible_versions.first() {
|
||||
// Check if the newest version is different and newer than installed
|
||||
if newest.id != installed_version_id
|
||||
&& newest.date_published > installed_version.date_published
|
||||
{
|
||||
return (true, Some(newest.id.clone()), Some((*newest).clone()));
|
||||
}
|
||||
if let Some(newest) = newer_versions.first() {
|
||||
return (true, Some(newest.id.clone()), Some((*newest).clone()));
|
||||
}
|
||||
|
||||
(false, None, None)
|
||||
@@ -306,10 +275,6 @@ pub async fn get_content_items(
|
||||
pool: &SqlitePool,
|
||||
fetch_semaphore: &FetchSemaphore,
|
||||
) -> crate::Result<Vec<ContentItem>> {
|
||||
let all_files = profile
|
||||
.get_projects(cache_behaviour, pool, fetch_semaphore)
|
||||
.await?;
|
||||
|
||||
let modpack_ids = if let Some(ref linked_data) = profile.linked_data {
|
||||
if linked_data.version_id.is_empty() {
|
||||
None
|
||||
@@ -350,23 +315,35 @@ pub async fn get_content_items(
|
||||
None
|
||||
};
|
||||
|
||||
let user_files: Vec<(String, ProfileFile)> = all_files
|
||||
.into_iter()
|
||||
.filter(|(_, file)| {
|
||||
modpack_ids
|
||||
.as_ref()
|
||||
.is_none_or(|ids| !ids.is_modpack_file(file))
|
||||
})
|
||||
.collect();
|
||||
let user_files: Vec<(String, ProfileFile)> = if let Some(ids) = &modpack_ids
|
||||
{
|
||||
let filtered_files = profile
|
||||
.get_projects_excluding_modpack_files(
|
||||
&ids.hashes,
|
||||
&ids.project_ids,
|
||||
cache_behaviour,
|
||||
pool,
|
||||
fetch_semaphore,
|
||||
)
|
||||
.await?;
|
||||
filtered_files.into_iter().collect()
|
||||
} else {
|
||||
let all_files = profile
|
||||
.get_projects(cache_behaviour, pool, fetch_semaphore)
|
||||
.await?;
|
||||
all_files.into_iter().collect()
|
||||
};
|
||||
|
||||
profile_files_to_content_items(
|
||||
let content_items = profile_files_to_content_items(
|
||||
&profile.path,
|
||||
&user_files,
|
||||
cache_behaviour,
|
||||
pool,
|
||||
fetch_semaphore,
|
||||
)
|
||||
.await
|
||||
.await?;
|
||||
|
||||
Ok(content_items)
|
||||
}
|
||||
|
||||
/// Pre-fetched metadata for projects, versions, teams, and organizations.
|
||||
|
||||
Reference in New Issue
Block a user