@@ -204,7 +196,14 @@
>
{{
- formatMessage(isApp ? messages.updateWarningApp : messages.updateWarningWeb)
+ warning ??
+ formatMessage(
+ incompatibilityWarningMode
+ ? messages.incompatibilityWarning
+ : isApp
+ ? messages.updateWarningApp
+ : messages.updateWarningWeb,
+ )
}}
@@ -214,23 +213,32 @@
{{ formatMessage(commonMessages.cancelButton) }}
-
+
-
+
+
{{
- formatMessage(
- isDowngrade
- ? messages.downgradeToVersion
- : switchMode
- ? messages.switchToVersion
- : messages.updateToVersion,
- {
- version: selectedVersion?.version_number ?? '...',
- },
- )
+ actionLoading
+ ? formatMessage(commonMessages.installingLabel)
+ : incompatibilityWarningMode
+ ? formatMessage(messages.installAnywayButton)
+ : formatMessage(
+ isDowngrade
+ ? messages.downgradeToVersion
+ : switchMode
+ ? messages.switchToVersion
+ : messages.updateToVersion,
+ {
+ version: selectedVersion?.version_number ?? '...',
+ },
+ )
}}
@@ -267,7 +275,12 @@ import {
TriangleAlertIcon,
XIcon,
} from '@modrinth/assets'
-import { capitalizeString, renderHighlightedString } from '@modrinth/utils'
+import {
+ capitalizeString,
+ formatVersionsForDisplay,
+ type GameVersionTag,
+ renderHighlightedString,
+} from '@modrinth/utils'
import { useTimeoutFn } from '@vueuse/core'
import { computed, ref, watch } from 'vue'
@@ -279,6 +292,7 @@ import NewModal from '#ui/components/modal/NewModal.vue'
import VersionChannelIndicator from '#ui/components/version/VersionChannelIndicator.vue'
import { useDebugLogger } from '#ui/composables/debug-logger'
import { defineMessages, useVIntl } from '#ui/composables/i18n'
+import { injectTags } from '#ui/providers'
import { commonMessages } from '#ui/utils/common-messages'
import {
versionChangesGameVersion,
@@ -287,12 +301,17 @@ import {
const { formatMessage } = useVIntl()
const debug = useDebugLogger('ContentUpdaterModal')
+const tags = injectTags(null)
const messages = defineMessages({
updateVersionHeader: {
id: 'instances.updater-modal.header',
defaultMessage: 'Update version',
},
+ incompatibilityWarningHeader: {
+ id: 'instances.updater-modal.incompatibility-warning-header',
+ defaultMessage: 'Choose version',
+ },
switchModpackVersionHeader: {
id: 'instances.updater-modal.header-modpack',
defaultMessage: 'Switch modpack version',
@@ -330,6 +349,11 @@ const messages = defineMessages({
id: 'instances.updater-modal.warning-web',
defaultMessage: 'Updating can break your world. Review version changelogs and back up first.',
},
+ incompatibilityWarning: {
+ id: 'instances.updater-modal.incompatibility-warning',
+ defaultMessage:
+ 'This version is not marked as compatible with this instance. Dependencies will not be installed automatically.',
+ },
downgradeToVersion: {
id: 'instances.updater-modal.downgrade-to',
defaultMessage: 'Downgrade to {version}',
@@ -375,6 +399,10 @@ const messages = defineMessages({
id: 'instances.updater-modal.incompatible-update.proceed',
defaultMessage: 'Update anyway',
},
+ installAnywayButton: {
+ id: 'instances.updater-modal.install-anyway',
+ defaultMessage: 'Install anyway',
+ },
})
const props = withDefaults(
@@ -389,6 +417,9 @@ const props = withDefaults(
projectIconUrl?: string
projectName?: string
header?: string
+ mode?: 'version' | 'incompatibility-warning'
+ warning?: string
+ actionLoading?: boolean
/** Whether versions are currently being loaded */
loading?: boolean
/** Whether changelog is being loaded for the selected version */
@@ -399,12 +430,29 @@ const props = withDefaults(
projectIconUrl: undefined,
projectName: undefined,
header: undefined,
+ mode: 'version',
+ warning: undefined,
+ actionLoading: false,
loading: false,
loadingChangelog: false,
},
)
const isModpack = computed(() => props.projectType === 'modpack')
+const incompatibilityWarningMode = computed(() => props.mode === 'incompatibility-warning')
+const defaultHeader = computed(() => {
+ if (incompatibilityWarningMode.value) {
+ return formatMessage(messages.incompatibilityWarningHeader)
+ }
+
+ return formatMessage(
+ isModpack.value
+ ? messages.switchModpackVersionHeader
+ : switchMode.value
+ ? messages.switchVersionHeader
+ : messages.updateVersionHeader,
+ )
+})
const emit = defineEmits<{
update: [version: Labrinth.Versions.v2.Version, event: MouseEvent]
@@ -424,6 +472,7 @@ const pendingIncompatibleUpdate = ref<{
version: Labrinth.Versions.v2.Version
event: MouseEvent
} | null>(null)
+const suppressCancelOnHide = ref(false)
// Store the initial version ID to select when versions become available
const pendingInitialVersionId = ref(undefined)
@@ -501,12 +550,16 @@ const filteredVersions = computed(() => {
if (searchQuery.value) {
const query = searchQuery.value.toLowerCase()
versions = versions.filter(
- (v) => v.name.toLowerCase().includes(query) || v.version_number.toLowerCase().includes(query),
+ (v) =>
+ v.name.toLowerCase().includes(query) ||
+ v.version_number.toLowerCase().includes(query) ||
+ (incompatibilityWarningMode.value &&
+ [...v.loaders, ...v.game_versions].some((value) => value.toLowerCase().includes(query))),
)
}
const beforeFilterCount = versions.length
- if (!isModpack.value && hideIncompatibleState.value) {
+ if (!incompatibilityWarningMode.value && !isModpack.value && hideIncompatibleState.value) {
versions = versions.filter(
(version) =>
version.id === props.currentVersionId ||
@@ -528,6 +581,7 @@ const filteredVersions = computed(() => {
})
function shouldShowBadge(version: Labrinth.Versions.v2.Version): boolean {
+ if (incompatibilityWarningMode.value) return false
return version.id === props.currentVersionId || shouldShowIncompatibleBadge(version)
}
@@ -587,8 +641,20 @@ function formatLongDate(dateString: string): string {
function formatLoaderGameVersion(version: Labrinth.Versions.v2.Version): string {
const loader = capitalizeString(version.loaders[0] || '')
- const gameVersion = version.game_versions[0] || ''
- return `${loader} ${gameVersion}`
+ const gameVersions = formatGameVersions(version)
+ return [loader, gameVersions].filter(Boolean).join(' ')
+}
+
+function formatGameVersions(version: Labrinth.Versions.v2.Version): string {
+ if (!incompatibilityWarningMode.value) {
+ return version.game_versions[0] || ''
+ }
+
+ const gameVersions = tags?.gameVersions.value?.length
+ ? formatVersionsForDisplay(version.game_versions, tags.gameVersions.value as GameVersionTag[])
+ : version.game_versions
+
+ return gameVersions.join(', ')
}
let prefetchTimeout: ReturnType | null = null
@@ -615,6 +681,11 @@ function handleVersionSelect(version: Labrinth.Versions.v2.Version) {
function handleUpdate(event: MouseEvent) {
if (selectedVersion.value) {
+ if (incompatibilityWarningMode.value) {
+ emitUpdate(selectedVersion.value, event, { hide: false })
+ return
+ }
+
const changesGameVersion = versionChangesGameVersion(
selectedVersion.value,
props.currentGameVersion,
@@ -679,9 +750,18 @@ function handleCancel() {
hide()
}
+function handleModalHide() {
+ if (suppressCancelOnHide.value) {
+ suppressCancelOnHide.value = false
+ return
+ }
+
+ emit('cancel')
+}
+
function show(initialVersionId?: string, options?: { switchMode?: boolean }) {
searchQuery.value = ''
- hideIncompatibleState.value = !isModpack.value
+ hideIncompatibleState.value = incompatibilityWarningMode.value ? false : !isModpack.value
pendingIncompatibleUpdate.value = null
switchMode.value = options?.switchMode ?? false
@@ -724,6 +804,7 @@ function show(initialVersionId?: string, options?: { switchMode?: boolean }) {
}
function hide() {
+ suppressCancelOnHide.value = true
modal.value?.hide()
}
diff --git a/packages/ui/src/locales/en-US/index.json b/packages/ui/src/locales/en-US/index.json
index 16f4663e2e..e54b42931a 100644
--- a/packages/ui/src/locales/en-US/index.json
+++ b/packages/ui/src/locales/en-US/index.json
@@ -1643,6 +1643,9 @@
"instances.content-install.header": {
"defaultMessage": "Install project"
},
+ "instances.content-install.incompatible-tooltip": {
+ "defaultMessage": "This instance uses a different loader or game version than this project supports."
+ },
"instances.content-install.install-button": {
"defaultMessage": "Install"
},
@@ -1715,6 +1718,12 @@
"instances.updater-modal.hide-incompatible": {
"defaultMessage": "Hide incompatible"
},
+ "instances.updater-modal.incompatibility-warning": {
+ "defaultMessage": "This version is not marked as compatible with this instance. Dependencies will not be installed automatically."
+ },
+ "instances.updater-modal.incompatibility-warning-header": {
+ "defaultMessage": "Choose version"
+ },
"instances.updater-modal.incompatible-update.description": {
"defaultMessage": "{version} is not marked as compatible with this installation. It may fail to launch or behave unexpectedly."
},
@@ -1724,6 +1733,9 @@
"instances.updater-modal.incompatible-update.proceed": {
"defaultMessage": "Update anyway"
},
+ "instances.updater-modal.install-anyway": {
+ "defaultMessage": "Install anyway"
+ },
"instances.updater-modal.loading-changelog": {
"defaultMessage": "Loading changelog..."
},