mirror of
https://github.com/modrinth/code.git
synced 2026-08-25 00:55:25 +00:00
feat: incompat modal improvement (#6256)
* feat: incompat modal improvement * feat: use ContentUpdaterModal and remove IncompatibilityWarningModal * fix: lint * fix: lint
This commit is contained in:
@@ -36,6 +36,7 @@ import {
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
ContentInstallModal,
|
||||
ContentUpdaterModal,
|
||||
CreationFlowModal,
|
||||
defineMessages,
|
||||
I18nDebugPanel,
|
||||
@@ -75,7 +76,6 @@ import Breadcrumbs from '@/components/ui/Breadcrumbs.vue'
|
||||
import ErrorModal from '@/components/ui/ErrorModal.vue'
|
||||
import FriendsList from '@/components/ui/friends/FriendsList.vue'
|
||||
import AddServerToInstanceModal from '@/components/ui/install_flow/AddServerToInstanceModal.vue'
|
||||
import IncompatibilityWarningModal from '@/components/ui/install_flow/IncompatibilityWarningModal.vue'
|
||||
import UnknownPackWarningModal from '@/components/ui/install_flow/UnknownPackWarningModal.vue'
|
||||
import MinecraftAuthErrorModal from '@/components/ui/minecraft-auth-error-modal/MinecraftAuthErrorModal.vue'
|
||||
import AppSettingsModal from '@/components/ui/modal/AppSettingsModal.vue'
|
||||
@@ -612,6 +612,16 @@ const {
|
||||
handleModpackDuplicateCreateAnyway: handleContentInstallModpackDuplicateCreateAnyway,
|
||||
handleModpackDuplicateGoToInstance: handleContentInstallModpackDuplicateGoToInstance,
|
||||
setIncompatibilityWarningModal: setContentIncompatibilityWarningModal,
|
||||
incompatibilityWarningVersions: contentInstallIncompatibilityWarningVersions,
|
||||
incompatibilityWarningCurrentGameVersion: contentInstallIncompatibilityWarningCurrentGameVersion,
|
||||
incompatibilityWarningCurrentLoader: contentInstallIncompatibilityWarningCurrentLoader,
|
||||
incompatibilityWarningProjectType: contentInstallIncompatibilityWarningProjectType,
|
||||
incompatibilityWarningProjectIconUrl: contentInstallIncompatibilityWarningProjectIconUrl,
|
||||
incompatibilityWarningProjectName: contentInstallIncompatibilityWarningProjectName,
|
||||
incompatibilityWarningMessage: contentInstallIncompatibilityWarningMessage,
|
||||
incompatibilityWarningInstalling: contentInstallIncompatibilityWarningInstalling,
|
||||
handleIncompatibilityWarningInstall: handleContentInstallIncompatibilityWarningInstall,
|
||||
handleIncompatibilityWarningCancel: handleContentInstallIncompatibilityWarningCancel,
|
||||
} = contentInstall
|
||||
|
||||
const serverInstall = createServerInstall({ router, handleError, popupNotificationManager })
|
||||
@@ -633,6 +643,12 @@ const updateToPlayModal = ref()
|
||||
|
||||
const modrinthLoginFlowWaitModal = ref()
|
||||
|
||||
watch(incompatibilityWarningModal, (modal) => {
|
||||
if (modal) {
|
||||
setContentIncompatibilityWarningModal(modal)
|
||||
}
|
||||
})
|
||||
|
||||
setupAuthProvider(credentials, async (_redirectPath) => {
|
||||
await signIn()
|
||||
})
|
||||
@@ -1631,7 +1647,22 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
@go-to-instance="handleModpackDuplicateGoToInstance"
|
||||
/>
|
||||
<AddServerToInstanceModal ref="addServerToInstanceModal" />
|
||||
<IncompatibilityWarningModal ref="incompatibilityWarningModal" />
|
||||
<ContentUpdaterModal
|
||||
ref="incompatibilityWarningModal"
|
||||
mode="incompatibility-warning"
|
||||
:versions="contentInstallIncompatibilityWarningVersions"
|
||||
:current-game-version="contentInstallIncompatibilityWarningCurrentGameVersion"
|
||||
:current-loader="contentInstallIncompatibilityWarningCurrentLoader"
|
||||
current-version-id=""
|
||||
:is-app="true"
|
||||
:project-type="contentInstallIncompatibilityWarningProjectType"
|
||||
:project-icon-url="contentInstallIncompatibilityWarningProjectIconUrl"
|
||||
:project-name="contentInstallIncompatibilityWarningProjectName"
|
||||
:warning="contentInstallIncompatibilityWarningMessage"
|
||||
:action-loading="contentInstallIncompatibilityWarningInstalling"
|
||||
@update="handleContentInstallIncompatibilityWarningInstall"
|
||||
@cancel="handleContentInstallIncompatibilityWarningCancel"
|
||||
/>
|
||||
<ModpackAlreadyInstalledModal
|
||||
ref="contentInstallModpackAlreadyInstalledModal"
|
||||
@create-anyway="handleContentInstallModpackDuplicateCreateAnyway"
|
||||
|
||||
@@ -1,185 +0,0 @@
|
||||
<template>
|
||||
<ModalWrapper ref="incompatibleModal" header="Incompatibility warning" :on-hide="onInstall">
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
This {{ versions?.length > 0 ? 'project' : 'version' }} is not compatible with the instance
|
||||
you're trying to install it on. Are you sure you want to continue? Dependencies will not be
|
||||
installed.
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr class="header">
|
||||
<th>{{ instance?.name }}</th>
|
||||
<th>{{ project.title }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="content">
|
||||
<td class="data">{{ instance?.loader }} {{ instance?.game_version }}</td>
|
||||
<td>
|
||||
<Combobox
|
||||
v-if="versions?.length > 1"
|
||||
v-model="selectedVersionId"
|
||||
:options="versionOptions"
|
||||
:searchable="true"
|
||||
placeholder="Select version"
|
||||
force-direction="up"
|
||||
:max-height="150"
|
||||
/>
|
||||
<span v-else>
|
||||
<span>{{ selectedVersionLabel }}</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="button-group">
|
||||
<ButtonStyled type="outlined">
|
||||
<button @click="() => incompatibleModal.hide()"><XIcon />Cancel</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand">
|
||||
<button :disabled="installing" @click="install()">
|
||||
<DownloadIcon /> {{ installing ? 'Installing' : 'Install' }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { DownloadIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
ButtonStyled,
|
||||
Combobox,
|
||||
formatLoader,
|
||||
injectNotificationManager,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { add_project_from_version as installMod } from '@/helpers/profile'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const instance = ref(null)
|
||||
const project = ref(null)
|
||||
const versions = ref(null)
|
||||
const selectedVersion = ref(null)
|
||||
const incompatibleModal = ref(null)
|
||||
const installing = ref(false)
|
||||
|
||||
const onInstall = ref(() => {})
|
||||
|
||||
const selectedVersionLabel = computed(() => {
|
||||
if (!selectedVersion.value) return ''
|
||||
return `${selectedVersion.value.name} (${selectedVersion.value.loaders
|
||||
.map((name) => formatLoader(formatMessage, name))
|
||||
.join(', ')} - ${selectedVersion.value.game_versions.join(', ')})`
|
||||
})
|
||||
|
||||
const versionOptions = computed(() =>
|
||||
(versions.value ?? []).map((version) => ({
|
||||
value: version.id,
|
||||
label: `${version.name} (${version.loaders
|
||||
.map((name) => formatLoader(formatMessage, name))
|
||||
.join(', ')} - ${version.game_versions.join(', ')})`,
|
||||
})),
|
||||
)
|
||||
|
||||
const selectedVersionId = computed({
|
||||
get: () => selectedVersion.value?.id ?? null,
|
||||
set: (value) => {
|
||||
if (!value) return
|
||||
selectedVersion.value = (versions.value ?? []).find((version) => version.id === value) ?? null
|
||||
},
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
show: (instanceVal, projectVal, projectVersions, selected, callback) => {
|
||||
instance.value = instanceVal
|
||||
versions.value = projectVersions ?? []
|
||||
selectedVersion.value = selected ?? projectVersions?.[0] ?? null
|
||||
|
||||
project.value = projectVal
|
||||
|
||||
onInstall.value = callback
|
||||
installing.value = false
|
||||
|
||||
incompatibleModal.value.show()
|
||||
|
||||
trackEvent('ProjectInstallStart', { source: 'ProjectIncompatibilityWarningModal' })
|
||||
},
|
||||
})
|
||||
|
||||
const install = async () => {
|
||||
installing.value = true
|
||||
await installMod(instance.value.path, selectedVersion.value.id, 'standalone').catch(handleError)
|
||||
installing.value = false
|
||||
onInstall.value(selectedVersion.value.id)
|
||||
incompatibleModal.value.hide()
|
||||
|
||||
trackEvent('ProjectInstall', {
|
||||
loader: instance.value.loader,
|
||||
game_version: instance.value.game_version,
|
||||
id: project.value,
|
||||
version_id: selectedVersion.value.id,
|
||||
project_type: project.value.project_type,
|
||||
title: project.value.title,
|
||||
source: 'ProjectIncompatibilityWarningModal',
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.data {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-radius: var(--radius-lg);
|
||||
border-collapse: collapse;
|
||||
box-shadow: 0 0 0 1px var(--color-button-bg);
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
padding: 1rem;
|
||||
background-color: var(--color-bg);
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid var(--color-button-bg);
|
||||
}
|
||||
|
||||
th:first-child {
|
||||
border-top-left-radius: var(--radius-lg);
|
||||
border-right: 1px solid var(--color-button-bg);
|
||||
}
|
||||
|
||||
th:last-child {
|
||||
border-top-right-radius: var(--radius-lg);
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
td:first-child {
|
||||
border-right: 1px solid var(--color-button-bg);
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
@@ -149,6 +149,9 @@
|
||||
"app.browse.server.installing": {
|
||||
"message": "Installing"
|
||||
},
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "No available versions match {compatibilityLabel}. Select a version to install anyway. Dependencies will not be installed automatically."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import type { ContentInstallInstance, ContentInstallProjectInfo, ContentItem } from '@modrinth/ui'
|
||||
import { createContext } from '@modrinth/ui'
|
||||
import { createContext, defineMessage, useVIntl } from '@modrinth/ui'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
import dayjs from 'dayjs'
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
} from '@/store/install.js'
|
||||
|
||||
interface ModalRef {
|
||||
show: () => void
|
||||
show: (initialVersionId?: string) => void
|
||||
hide: () => void
|
||||
}
|
||||
|
||||
@@ -42,19 +42,14 @@ interface ModpackAlreadyInstalledModalRef {
|
||||
show: (instanceName: string, instancePath: string) => void
|
||||
}
|
||||
|
||||
interface IncompatibilityWarningModalRef {
|
||||
show: (
|
||||
instance: GameInstance,
|
||||
project: Labrinth.Projects.v2.Project,
|
||||
versions: Labrinth.Versions.v2.Version[],
|
||||
version: Labrinth.Versions.v2.Version,
|
||||
callback: (versionId?: string) => void,
|
||||
) => void
|
||||
}
|
||||
|
||||
const LOADER_ORDER = ['vanilla', 'fabric', 'quilt', 'neoforge', 'forge']
|
||||
const SUPPORTED_LOADERS: Set<string> = new Set(['vanilla', 'forge', 'fabric', 'quilt', 'neoforge'])
|
||||
const VANILLA_COMPATIBLE_LOADERS: Set<string> = new Set(['minecraft', 'datapack'])
|
||||
const noCompatibleVersionsMessage = defineMessage({
|
||||
id: 'app.content-install.no-compatible-versions',
|
||||
defaultMessage:
|
||||
'No available versions match {compatibilityLabel}. Select a version to install anyway. Dependencies will not be installed automatically.',
|
||||
})
|
||||
|
||||
function sortLoaders(loaders: string[]): string[] {
|
||||
return loaders.slice().sort((a, b) => {
|
||||
@@ -91,7 +86,17 @@ export interface ContentInstallContext {
|
||||
setModpackAlreadyInstalledModal: (ref: ModpackAlreadyInstalledModalRef) => void
|
||||
handleModpackDuplicateCreateAnyway: () => Promise<void>
|
||||
handleModpackDuplicateGoToInstance: (instancePath: string) => void
|
||||
setIncompatibilityWarningModal: (ref: IncompatibilityWarningModalRef) => void
|
||||
setIncompatibilityWarningModal: (ref: ModalRef) => void
|
||||
incompatibilityWarningVersions: Ref<Labrinth.Versions.v2.Version[]>
|
||||
incompatibilityWarningCurrentGameVersion: Ref<string>
|
||||
incompatibilityWarningCurrentLoader: Ref<string>
|
||||
incompatibilityWarningProjectType: Ref<string | undefined>
|
||||
incompatibilityWarningProjectIconUrl: Ref<string | undefined>
|
||||
incompatibilityWarningProjectName: Ref<string | undefined>
|
||||
incompatibilityWarningMessage: Ref<string | undefined>
|
||||
incompatibilityWarningInstalling: Ref<boolean>
|
||||
handleIncompatibilityWarningInstall: (version: Labrinth.Versions.v2.Version) => Promise<void>
|
||||
handleIncompatibilityWarningCancel: () => void
|
||||
install: (
|
||||
projectId: string,
|
||||
versionId?: string | null,
|
||||
@@ -113,6 +118,7 @@ export function createContentInstall(opts: {
|
||||
router: Router
|
||||
handleError: (err: unknown) => void
|
||||
}): ContentInstallContext {
|
||||
const { formatMessage } = useVIntl()
|
||||
const instances = ref<ContentInstallInstance[]>([])
|
||||
const compatibleLoaders = ref<string[]>([])
|
||||
const gameVersions = ref<string[]>([])
|
||||
@@ -124,6 +130,14 @@ export function createContentInstall(opts: {
|
||||
|
||||
const projectInfo = ref<ContentInstallProjectInfo | null>(null)
|
||||
const installingItems = ref<Map<string, ContentItem[]>>(new Map())
|
||||
const incompatibilityWarningVersions = ref<Labrinth.Versions.v2.Version[]>([])
|
||||
const incompatibilityWarningCurrentGameVersion = ref('')
|
||||
const incompatibilityWarningCurrentLoader = ref('')
|
||||
const incompatibilityWarningProjectType = ref<string | undefined>(undefined)
|
||||
const incompatibilityWarningProjectIconUrl = ref<string | undefined>(undefined)
|
||||
const incompatibilityWarningProjectName = ref<string | undefined>(undefined)
|
||||
const incompatibilityWarningMessage = ref<string | undefined>(undefined)
|
||||
const incompatibilityWarningInstalling = ref(false)
|
||||
|
||||
function addInstallingItem(
|
||||
instancePath: string,
|
||||
@@ -239,11 +253,15 @@ export function createContentInstall(opts: {
|
||||
|
||||
let modalRef: ModalRef | null = null
|
||||
let modpackAlreadyInstalledModalRef: ModpackAlreadyInstalledModalRef | null = null
|
||||
let incompatibilityWarningModalRef: IncompatibilityWarningModalRef | null = null
|
||||
let incompatibilityWarningModalRef: ModalRef | null = null
|
||||
let currentProject: Labrinth.Projects.v2.Project | null = null
|
||||
let currentVersions: Labrinth.Versions.v2.Version[] = []
|
||||
let currentCallback: (versionId?: string) => void = () => {}
|
||||
let profileMap: Record<string, GameInstance> = {}
|
||||
let incompatibilityWarningInstance: GameInstance | null = null
|
||||
let incompatibilityWarningProject: Labrinth.Projects.v2.Project | null = null
|
||||
let incompatibilityWarningCallback: (versionId?: string) => void = () => {}
|
||||
let incompatibilityWarningInstalled = false
|
||||
|
||||
let pendingModpackInstall: {
|
||||
project: Labrinth.Projects.v2.Project
|
||||
@@ -410,15 +428,35 @@ export function createContentInstall(opts: {
|
||||
async function handleInstallToInstance(instance: ContentInstallInstance) {
|
||||
const profile = profileMap[instance.id]
|
||||
const storeInstance = instances.value.find((i) => i.id === instance.id)
|
||||
if (storeInstance) storeInstance.installing = true
|
||||
if (!currentProject || !profile) {
|
||||
opts.handleError('No project or instance found')
|
||||
return
|
||||
}
|
||||
|
||||
const version = findPreferredVersion(currentVersions, currentProject, profile)
|
||||
if (!version) {
|
||||
if (storeInstance) storeInstance.installing = false
|
||||
opts.handleError('No compatible version found')
|
||||
if (currentVersions.length > 0 && incompatibilityWarningModalRef) {
|
||||
const onIncompatibleInstall = (versionId?: string) => {
|
||||
if (versionId && storeInstance) {
|
||||
storeInstance.installed = true
|
||||
}
|
||||
currentCallback(versionId)
|
||||
}
|
||||
await showIncompatibilityWarning(
|
||||
profile,
|
||||
currentProject,
|
||||
currentVersions,
|
||||
currentVersions[0],
|
||||
onIncompatibleInstall,
|
||||
)
|
||||
} else {
|
||||
opts.handleError('No version found')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (storeInstance) storeInstance.installing = true
|
||||
|
||||
const installedProjectIds: string[] = []
|
||||
if (currentProject) {
|
||||
addInstallingItem(instance.id, currentProject, version)
|
||||
@@ -458,6 +496,73 @@ export function createContentInstall(opts: {
|
||||
}
|
||||
}
|
||||
|
||||
async function showIncompatibilityWarning(
|
||||
instance: GameInstance,
|
||||
project: Labrinth.Projects.v2.Project,
|
||||
versions: Labrinth.Versions.v2.Version[],
|
||||
version: Labrinth.Versions.v2.Version,
|
||||
callback: (versionId?: string) => void,
|
||||
) {
|
||||
incompatibilityWarningInstance = instance
|
||||
incompatibilityWarningProject = project
|
||||
incompatibilityWarningCallback = callback
|
||||
incompatibilityWarningInstalled = false
|
||||
incompatibilityWarningInstalling.value = false
|
||||
incompatibilityWarningVersions.value = versions
|
||||
incompatibilityWarningCurrentGameVersion.value = instance.game_version ?? ''
|
||||
incompatibilityWarningCurrentLoader.value = instance.loader ?? ''
|
||||
incompatibilityWarningProjectType.value = project.project_type
|
||||
incompatibilityWarningProjectIconUrl.value = project.icon_url ?? undefined
|
||||
incompatibilityWarningProjectName.value = project.title
|
||||
|
||||
const compatibilityLabel =
|
||||
project.project_type === 'resourcepack' || project.project_type === 'datapack'
|
||||
? (instance.game_version ?? '')
|
||||
: `${instance.loader ?? ''} ${instance.game_version ?? ''}`.trim()
|
||||
incompatibilityWarningMessage.value = formatMessage(noCompatibleVersionsMessage, {
|
||||
compatibilityLabel,
|
||||
})
|
||||
|
||||
await nextTick()
|
||||
incompatibilityWarningModalRef?.show(version.id)
|
||||
trackEvent('ProjectInstallStart', { source: 'ProjectIncompatibilityWarningModal' })
|
||||
}
|
||||
|
||||
async function handleIncompatibilityWarningInstall(version: Labrinth.Versions.v2.Version) {
|
||||
if (!incompatibilityWarningInstance || !incompatibilityWarningProject) return
|
||||
|
||||
incompatibilityWarningInstalling.value = true
|
||||
try {
|
||||
await add_project_from_version(incompatibilityWarningInstance.path, version.id, 'standalone')
|
||||
} catch (err) {
|
||||
opts.handleError(err)
|
||||
incompatibilityWarningInstalling.value = false
|
||||
return
|
||||
}
|
||||
|
||||
incompatibilityWarningInstalling.value = false
|
||||
incompatibilityWarningInstalled = true
|
||||
incompatibilityWarningCallback(version.id)
|
||||
incompatibilityWarningModalRef?.hide()
|
||||
|
||||
trackEvent('ProjectInstall', {
|
||||
loader: incompatibilityWarningInstance.loader,
|
||||
game_version: incompatibilityWarningInstance.game_version,
|
||||
id: incompatibilityWarningProject.id,
|
||||
version_id: version.id,
|
||||
project_type: incompatibilityWarningProject.project_type,
|
||||
title: incompatibilityWarningProject.title,
|
||||
source: 'ProjectIncompatibilityWarningModal',
|
||||
})
|
||||
}
|
||||
|
||||
function handleIncompatibilityWarningCancel() {
|
||||
if (!incompatibilityWarningInstalled) {
|
||||
incompatibilityWarningCallback()
|
||||
}
|
||||
incompatibilityWarningInstalled = false
|
||||
}
|
||||
|
||||
async function handleCreateAndInstall(data: {
|
||||
name: string
|
||||
iconPath: string | null
|
||||
@@ -614,7 +719,7 @@ export function createContentInstall(opts: {
|
||||
removeInstallingItems(instancePath, installedProjectIds)
|
||||
}
|
||||
} else {
|
||||
incompatibilityWarningModalRef?.show(instance, project, projectVersions, version, callback)
|
||||
await showIncompatibilityWarning(instance, project, projectVersions, version, callback)
|
||||
}
|
||||
} else {
|
||||
let versions = (
|
||||
@@ -668,9 +773,19 @@ export function createContentInstall(opts: {
|
||||
pendingModpackInstall = null
|
||||
opts.router.push(`/instance/${encodeURIComponent(instancePath)}`)
|
||||
},
|
||||
setIncompatibilityWarningModal(ref: IncompatibilityWarningModalRef) {
|
||||
setIncompatibilityWarningModal(ref: ModalRef) {
|
||||
incompatibilityWarningModalRef = ref
|
||||
},
|
||||
incompatibilityWarningVersions,
|
||||
incompatibilityWarningCurrentGameVersion,
|
||||
incompatibilityWarningCurrentLoader,
|
||||
incompatibilityWarningProjectType,
|
||||
incompatibilityWarningProjectIconUrl,
|
||||
incompatibilityWarningProjectName,
|
||||
incompatibilityWarningMessage,
|
||||
incompatibilityWarningInstalling,
|
||||
handleIncompatibilityWarningInstall,
|
||||
handleIncompatibilityWarningCancel,
|
||||
install,
|
||||
installingItems,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user