From 43190707a92c5428d3a21b7d5aaae66619e6a591 Mon Sep 17 00:00:00 2001
From: "Calum H. (IMB11)"
Date: Fri, 29 May 2026 18:52:29 +0100
Subject: [PATCH 1/6] feat: rough release channels impl draft
---
.../InstallationSettings.vue | 4 +
apps/app-frontend/src/helpers/types.d.ts | 1 +
apps/app-frontend/src/pages/instance/Mods.vue | 9 ++
apps/app/src/api/profile.rs | 6 ++
...8f4ec2e248f751f98140f77bea4f9d5971ef1.json | 12 ---
...dc80e96f68e8f5fd54fa2f2e9c55a8fffdc28.json | 12 +++
...f2cd2991b4f4b1200135be79ec61827008f0.json} | 40 ++++---
...0b2f10b52eeb4b074a3da2b1961cb2861155.json} | 40 ++++---
...60529120000_profile-prerelease-updates.sql | 2 +
packages/app-lib/src/api/profile/create.rs | 1 +
packages/app-lib/src/state/cache.rs | 101 +++++++++++++++---
.../app-lib/src/state/instances/content.rs | 10 +-
.../app-lib/src/state/legacy_converter.rs | 11 +-
packages/app-lib/src/state/profiles.rs | 69 +++++++-----
.../src/layouts/shared/content-tab/index.ts | 1 +
.../content-tab/utils/update-channels.ts | 33 ++++++
.../shared/installation-settings/layout.vue | 30 ++++++
.../providers/installation-settings.ts | 3 +
18 files changed, 292 insertions(+), 93 deletions(-)
delete mode 100644 packages/app-lib/.sqlx/query-27283e20fc86c941c7d6d09259d8f4ec2e248f751f98140f77bea4f9d5971ef1.json
create mode 100644 packages/app-lib/.sqlx/query-4c7d0bb4d93ab74de69a15690dadc80e96f68e8f5fd54fa2f2e9c55a8fffdc28.json
rename packages/app-lib/.sqlx/{query-6a434cc55635b6e325e9e5f06d21b787af281db4402c8ff45fe6a77b5be6c929.json => query-52a6997ba6aab38e36d72cc6e860f2cd2991b4f4b1200135be79ec61827008f0.json} (81%)
rename packages/app-lib/.sqlx/{query-c108849d77c7627d6a11d5be34984938c41283e6091a1301fc3ca0b355ffcfa9.json => query-cf15ce2acd08c53a7415c73daa6b0b2f10b52eeb4b074a3da2b1961cb2861155.json} (81%)
create mode 100644 packages/app-lib/migrations/20260529120000_profile-prerelease-updates.sql
create mode 100644 packages/ui/src/layouts/shared/content-tab/utils/update-channels.ts
diff --git a/apps/app-frontend/src/components/ui/instance_settings/InstallationSettings.vue b/apps/app-frontend/src/components/ui/instance_settings/InstallationSettings.vue
index 4b1e5af378..50d9b2630a 100644
--- a/apps/app-frontend/src/components/ui/instance_settings/InstallationSettings.vue
+++ b/apps/app-frontend/src/components/ui/instance_settings/InstallationSettings.vue
@@ -273,6 +273,10 @@ provideInstallationSettings({
isServer: false,
isApp: true,
showModpackVersionActions: !isMinecraftServer.value,
+ showPrereleaseUpdates: computed(() => instance.value.show_prerelease_updates),
+ setShowPrereleaseUpdates: async (value: boolean) => {
+ await edit(instance.value.path, { show_prerelease_updates: value }).catch(handleError)
+ },
repairing,
reinstalling,
})
diff --git a/apps/app-frontend/src/helpers/types.d.ts b/apps/app-frontend/src/helpers/types.d.ts
index 7c5f1d25e7..052ad1071e 100644
--- a/apps/app-frontend/src/helpers/types.d.ts
+++ b/apps/app-frontend/src/helpers/types.d.ts
@@ -14,6 +14,7 @@ export type GameInstance = {
groups: string[]
linked_data?: LinkedData
+ show_prerelease_updates: boolean
created: Date
modified: Date
diff --git a/apps/app-frontend/src/pages/instance/Mods.vue b/apps/app-frontend/src/pages/instance/Mods.vue
index f64101f56a..befec2e70f 100644
--- a/apps/app-frontend/src/pages/instance/Mods.vue
+++ b/apps/app-frontend/src/pages/instance/Mods.vue
@@ -1194,6 +1194,15 @@ watch(
},
)
+watch(
+ () => props.instance?.show_prerelease_updates,
+ async (newValue, oldValue) => {
+ if (newValue !== oldValue) {
+ await initProjects('must_revalidate')
+ }
+ },
+)
+
onUnmounted(() => {
isUnmounted = true
removeBeforeEach()
diff --git a/apps/app/src/api/profile.rs b/apps/app/src/api/profile.rs
index d33d3a3f2b..57048e9805 100644
--- a/apps/app/src/api/profile.rs
+++ b/apps/app/src/api/profile.rs
@@ -385,6 +385,7 @@ pub struct EditProfile {
with = "serde_with::rust::double_option"
)]
pub linked_data: Option
+
+
+ {{ formatMessage(messages.updateChannel) }}
+
+
+
+ {{ formatReleaseChannelDescription(selectedReleaseChannel) }}
+
+
+
{{ formatMessage(messages.deleteInstance) }}
diff --git a/apps/app-frontend/src/components/ui/instance_settings/InstallationSettings.vue b/apps/app-frontend/src/components/ui/instance_settings/InstallationSettings.vue
index 19909ba949..4b1e5af378 100644
--- a/apps/app-frontend/src/components/ui/instance_settings/InstallationSettings.vue
+++ b/apps/app-frontend/src/components/ui/instance_settings/InstallationSettings.vue
@@ -273,13 +273,6 @@ provideInstallationSettings({
isServer: false,
isApp: true,
showModpackVersionActions: !isMinecraftServer.value,
- showPrereleaseUpdates: computed(() => instance.value.show_prerelease_updates),
- setShowPrereleaseUpdates: async (value: boolean) => {
- const profilePath = instance.value.path
- await edit(profilePath, { show_prerelease_updates: value })
- .then(() => queryClient.invalidateQueries({ queryKey: ['linkedModpackInfo', profilePath] }))
- .catch(handleError)
- },
repairing,
reinstalling,
})
diff --git a/apps/app-frontend/src/helpers/types.d.ts b/apps/app-frontend/src/helpers/types.d.ts
index 052ad1071e..143997702f 100644
--- a/apps/app-frontend/src/helpers/types.d.ts
+++ b/apps/app-frontend/src/helpers/types.d.ts
@@ -14,7 +14,7 @@ export type GameInstance = {
groups: string[]
linked_data?: LinkedData
- show_prerelease_updates: boolean
+ preferred_update_channel: ReleaseChannel
created: Date
modified: Date
@@ -47,6 +47,8 @@ type LinkedData = {
locked: boolean
}
+type ReleaseChannel = 'release' | 'beta' | 'alpha'
+
export type InstanceLoader = 'vanilla' | 'forge' | 'fabric' | 'quilt' | 'neoforge'
type ContentFile = {
diff --git a/apps/app-frontend/src/pages/instance/Mods.vue b/apps/app-frontend/src/pages/instance/Mods.vue
index befec2e70f..d3a8004e07 100644
--- a/apps/app-frontend/src/pages/instance/Mods.vue
+++ b/apps/app-frontend/src/pages/instance/Mods.vue
@@ -1195,7 +1195,7 @@ watch(
)
watch(
- () => props.instance?.show_prerelease_updates,
+ () => props.instance?.preferred_update_channel,
async (newValue, oldValue) => {
if (newValue !== oldValue) {
await initProjects('must_revalidate')
diff --git a/apps/app/src/api/profile.rs b/apps/app/src/api/profile.rs
index 57048e9805..e35a3675c1 100644
--- a/apps/app/src/api/profile.rs
+++ b/apps/app/src/api/profile.rs
@@ -385,7 +385,7 @@ pub struct EditProfile {
with = "serde_with::rust::double_option"
)]
pub linked_data: Option
diff --git a/packages/ui/src/layouts/shared/installation-settings/providers/installation-settings.ts b/packages/ui/src/layouts/shared/installation-settings/providers/installation-settings.ts
index 1aaa1f3741..0b543d6f66 100644
--- a/packages/ui/src/layouts/shared/installation-settings/providers/installation-settings.ts
+++ b/packages/ui/src/layouts/shared/installation-settings/providers/installation-settings.ts
@@ -57,9 +57,6 @@ export interface InstallationSettingsContext {
/** When false, hides change-version and reinstall buttons in linked state (default: true) */
showModpackVersionActions?: boolean | ComputedRef
- showPrereleaseUpdates?: Ref | ComputedRef
- setShowPrereleaseUpdates?: (value: boolean) => Promise
-
/** True when the linked modpack was uploaded as a local file rather than from Modrinth */
isLocalFile?: boolean | ComputedRef
diff --git a/packages/ui/src/locales/en-US/index.json b/packages/ui/src/locales/en-US/index.json
index 0c8f515cf7..c7520ca2be 100644
--- a/packages/ui/src/locales/en-US/index.json
+++ b/packages/ui/src/locales/en-US/index.json
@@ -1565,12 +1565,6 @@
"installation-settings.search-game-version": {
"defaultMessage": "Search game version..."
},
- "installation-settings.show-prerelease-updates.description": {
- "defaultMessage": "Shows prerelease project versions as available updates for this instance."
- },
- "installation-settings.show-prerelease-updates.title": {
- "defaultMessage": "Show beta and alpha updates"
- },
"installation-settings.type.instance": {
"defaultMessage": "instance"
},
From cf8c1e3528b29a3387b9f24bda40d6dfd52e91f2 Mon Sep 17 00:00:00 2001
From: "Calum H. (IMB11)"
Date: Sat, 30 May 2026 19:08:35 +0100
Subject: [PATCH 5/6] fix: lint
---
.../app-frontend/src/locales/en-US/index.json | 24 +++++++++++++++++++
packages/app-lib/src/state/cache.rs | 6 +++--
.../app-lib/src/state/legacy_converter.rs | 4 ++--
packages/app-lib/src/state/profiles.rs | 11 ++++-----
.../content-tab/utils/update-channels.ts | 4 +++-
5 files changed, 38 insertions(+), 11 deletions(-)
diff --git a/apps/app-frontend/src/locales/en-US/index.json b/apps/app-frontend/src/locales/en-US/index.json
index 8b04360fe8..fd23286a14 100644
--- a/apps/app-frontend/src/locales/en-US/index.json
+++ b/apps/app-frontend/src/locales/en-US/index.json
@@ -695,6 +695,30 @@
"instance.settings.tabs.general.name": {
"message": "Name"
},
+ "instance.settings.tabs.general.update-channel": {
+ "message": "Update channel"
+ },
+ "instance.settings.tabs.general.update-channel.alpha": {
+ "message": "Alpha"
+ },
+ "instance.settings.tabs.general.update-channel.alpha.description": {
+ "message": "Stable release, beta, and alpha versions will be shown as available updates."
+ },
+ "instance.settings.tabs.general.update-channel.beta": {
+ "message": "Beta"
+ },
+ "instance.settings.tabs.general.update-channel.beta.description": {
+ "message": "Stable release and beta versions will be shown as available updates."
+ },
+ "instance.settings.tabs.general.update-channel.release": {
+ "message": "Release"
+ },
+ "instance.settings.tabs.general.update-channel.release.description": {
+ "message": "Only stable release versions will be shown as available updates."
+ },
+ "instance.settings.tabs.general.update-channel.select": {
+ "message": "Select update channel"
+ },
"instance.settings.tabs.hooks": {
"message": "Launch hooks"
},
diff --git a/packages/app-lib/src/state/cache.rs b/packages/app-lib/src/state/cache.rs
index 15c8c8d54a..64a3d7b22c 100644
--- a/packages/app-lib/src/state/cache.rs
+++ b/packages/app-lib/src/state/cache.rs
@@ -1534,8 +1534,10 @@ impl CachedEntry {
let key = string.splitn(4, '-').collect::>();
let parsed_key = if key.len() == 4
- && matches!(key[2], "release" | "beta" | "alpha" | "all")
- {
+ && matches!(
+ key[2],
+ "release" | "beta" | "alpha" | "all"
+ ) {
Some((key[0], key[1], key[2], key[3]))
} else {
let key = string.splitn(3, '-').collect::>();
diff --git a/packages/app-lib/src/state/legacy_converter.rs b/packages/app-lib/src/state/legacy_converter.rs
index 8f65955e65..54ca5a1734 100644
--- a/packages/app-lib/src/state/legacy_converter.rs
+++ b/packages/app-lib/src/state/legacy_converter.rs
@@ -6,8 +6,8 @@ use crate::state::{
CacheValue, CachedEntry, CachedFile, CachedFileHash, CachedFileUpdate,
Credentials, DefaultPage, DependencyType, DeviceToken, DeviceTokenKey,
DeviceTokenPair, FileType, Hooks, LauncherFeatureVersion, LinkedData,
- MemorySettings, ModrinthCredentials, ReleaseChannel,
- Profile, ProfileInstallStage, TeamMember, Theme, VersionFile, WindowSize,
+ MemorySettings, ModrinthCredentials, Profile, ProfileInstallStage,
+ ReleaseChannel, TeamMember, Theme, VersionFile, WindowSize,
};
use crate::util::fetch::{IoSemaphore, read_json};
use chrono::{DateTime, Utc};
diff --git a/packages/app-lib/src/state/profiles.rs b/packages/app-lib/src/state/profiles.rs
index c457d7a336..a1a2166a38 100644
--- a/packages/app-lib/src/state/profiles.rs
+++ b/packages/app-lib/src/state/profiles.rs
@@ -753,15 +753,15 @@ impl Profile {
let file_updates = file_hashes
.iter()
.filter_map(|file| {
- all.iter()
- .find(|prof| file.path.contains(&prof.path))
- .map(|profile| {
+ all.iter().find(|prof| file.path.contains(&prof.path)).map(
+ |profile| {
Self::get_cache_key(
file,
profile,
profile.preferred_update_channel,
)
- })
+ },
+ )
})
.collect::>();
@@ -1186,8 +1186,7 @@ impl Profile {
return Ok(HashMap::new());
}
- let version_ids_ref =
- version_ids.iter().copied().collect::>();
+ let version_ids_ref = version_ids.iter().copied().collect::>();
let versions = CachedEntry::get_version_many(
&version_ids_ref,
cache_behaviour,
diff --git a/packages/ui/src/layouts/shared/content-tab/utils/update-channels.ts b/packages/ui/src/layouts/shared/content-tab/utils/update-channels.ts
index 0e7a760e28..088f65b276 100644
--- a/packages/ui/src/layouts/shared/content-tab/utils/update-channels.ts
+++ b/packages/ui/src/layouts/shared/content-tab/utils/update-channels.ts
@@ -57,7 +57,9 @@ export function newestEligibleUpdate(
const effectivePolicy = effectiveUpdateChannel(policy, currentVersionType)
for (const versionTypes of channelFallbacks(effectivePolicy)) {
- if (!versions.some((version) => versionTypes.includes(normalizeChannel(version.version_type)))) {
+ if (
+ !versions.some((version) => versionTypes.includes(normalizeChannel(version.version_type)))
+ ) {
continue
}
From fdd991f70432dcfbd656b63f31b8dfa93fc4f4d1 Mon Sep 17 00:00:00 2001
From: "Calum H. (IMB11)"
Date: Mon, 1 Jun 2026 12:58:04 +0100
Subject: [PATCH 6/6] fix: copy
---
.../src/components/ui/instance_settings/GeneralSettings.vue | 6 +++---
apps/app-frontend/src/locales/en-US/index.json | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/apps/app-frontend/src/components/ui/instance_settings/GeneralSettings.vue b/apps/app-frontend/src/components/ui/instance_settings/GeneralSettings.vue
index ace17cb2e6..e30bead729 100644
--- a/apps/app-frontend/src/components/ui/instance_settings/GeneralSettings.vue
+++ b/apps/app-frontend/src/components/ui/instance_settings/GeneralSettings.vue
@@ -237,15 +237,15 @@ const messages = defineMessages({
},
updateChannelReleaseDescription: {
id: 'instance.settings.tabs.general.update-channel.release.description',
- defaultMessage: 'Only stable release versions will be shown as available updates.',
+ defaultMessage: 'Only release versions will be shown as available updates.',
},
updateChannelBetaDescription: {
id: 'instance.settings.tabs.general.update-channel.beta.description',
- defaultMessage: 'Stable release and beta versions will be shown as available updates.',
+ defaultMessage: 'Release and beta versions will be shown as available updates.',
},
updateChannelAlphaDescription: {
id: 'instance.settings.tabs.general.update-channel.alpha.description',
- defaultMessage: 'Stable release, beta, and alpha versions will be shown as available updates.',
+ defaultMessage: 'Release, beta, and alpha versions will be shown as available updates.',
},
updateChannelRelease: {
id: 'instance.settings.tabs.general.update-channel.release',
diff --git a/apps/app-frontend/src/locales/en-US/index.json b/apps/app-frontend/src/locales/en-US/index.json
index b27a2d5355..f0345af27b 100644
--- a/apps/app-frontend/src/locales/en-US/index.json
+++ b/apps/app-frontend/src/locales/en-US/index.json
@@ -711,19 +711,19 @@
"message": "Alpha"
},
"instance.settings.tabs.general.update-channel.alpha.description": {
- "message": "Stable release, beta, and alpha versions will be shown as available updates."
+ "message": "Release, beta, and alpha versions will be shown as available updates."
},
"instance.settings.tabs.general.update-channel.beta": {
"message": "Beta"
},
"instance.settings.tabs.general.update-channel.beta.description": {
- "message": "Stable release and beta versions will be shown as available updates."
+ "message": "Release and beta versions will be shown as available updates."
},
"instance.settings.tabs.general.update-channel.release": {
"message": "Release"
},
"instance.settings.tabs.general.update-channel.release.description": {
- "message": "Only stable release versions will be shown as available updates."
+ "message": "Only release versions will be shown as available updates."
},
"instance.settings.tabs.general.update-channel.select": {
"message": "Select update channel"