You've already forked AstralRinth
forked from didirus/AstralRinth
Handle project type on per version basis for multi-type projects (#4945)
* infer project type by draft version loader * fix detecting modpack project type when editing * fix no loaders check * pnpm run fix
This commit is contained in:
@@ -22,7 +22,7 @@ const modal = useTemplateRef<ComponentExposed<typeof MultiStageModal>>('modal')
|
|||||||
const ctx = createManageVersionContext(modal)
|
const ctx = createManageVersionContext(modal)
|
||||||
provideManageVersionContext(ctx)
|
provideManageVersionContext(ctx)
|
||||||
|
|
||||||
const { newDraftVersion, setProjectType } = ctx
|
const { newDraftVersion } = ctx
|
||||||
|
|
||||||
const { projectV2 } = injectProjectPageContext()
|
const { projectV2 } = injectProjectPageContext()
|
||||||
const { addNotification } = injectNotificationManager()
|
const { addNotification } = injectNotificationManager()
|
||||||
@@ -62,7 +62,6 @@ function openCreateVersionModal(
|
|||||||
stageId: string | null = null,
|
stageId: string | null = null,
|
||||||
) {
|
) {
|
||||||
newDraftVersion(projectV2.value.id, version)
|
newDraftVersion(projectV2.value.id, version)
|
||||||
setProjectType(projectV2.value)
|
|
||||||
modal.value?.setStage(stageId ?? 0)
|
modal.value?.setStage(stageId ?? 0)
|
||||||
modal.value?.show()
|
modal.value?.show()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,9 +103,7 @@ const {
|
|||||||
existingFilesToDelete,
|
existingFilesToDelete,
|
||||||
setPrimaryFile,
|
setPrimaryFile,
|
||||||
setInferredVersionData,
|
setInferredVersionData,
|
||||||
setProjectType,
|
|
||||||
editingVersion,
|
editingVersion,
|
||||||
projectType,
|
|
||||||
} = injectManageVersionContext()
|
} = injectManageVersionContext()
|
||||||
|
|
||||||
const addDetectedData = async () => {
|
const addDetectedData = async () => {
|
||||||
@@ -125,17 +123,9 @@ const addDetectedData = async () => {
|
|||||||
...draftVersion.value,
|
...draftVersion.value,
|
||||||
...mappedInferredData,
|
...mappedInferredData,
|
||||||
}
|
}
|
||||||
|
|
||||||
setProjectType(projectV2.value, primaryFile)
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error parsing version file data', err)
|
console.error('Error parsing version file data', err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (projectType.value === 'resourcepack') {
|
|
||||||
draftVersion.value.loaders = ['minecraft']
|
|
||||||
} else if (projectType.value === 'modpack' && draftVersion.value.loaders?.length === 0) {
|
|
||||||
draftVersion.value.loaders = ['minecraft']
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add detected data when the primary file changes
|
// add detected data when the primary file changes
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { XIcon } from '@modrinth/assets'
|
import { XIcon } from '@modrinth/assets'
|
||||||
import { ButtonStyled, injectProjectPageContext, TagItem } from '@modrinth/ui'
|
import { ButtonStyled, TagItem } from '@modrinth/ui'
|
||||||
import { formatCategory } from '@modrinth/utils'
|
import { formatCategory } from '@modrinth/utils'
|
||||||
|
|
||||||
import { injectManageVersionContext } from '~/providers/version/manage-version-modal'
|
import { injectManageVersionContext } from '~/providers/version/manage-version-modal'
|
||||||
@@ -51,10 +51,9 @@ import LoaderPicker from '../components/LoaderPicker.vue'
|
|||||||
|
|
||||||
const generatedState = useGeneratedState()
|
const generatedState = useGeneratedState()
|
||||||
|
|
||||||
const { projectV2 } = injectProjectPageContext()
|
|
||||||
const loaders = computed(() => generatedState.value.loaders)
|
const loaders = computed(() => generatedState.value.loaders)
|
||||||
|
|
||||||
const { draftVersion, setProjectType } = injectManageVersionContext()
|
const { draftVersion } = injectManageVersionContext()
|
||||||
|
|
||||||
const toggleLoader = (loader: string) => {
|
const toggleLoader = (loader: string) => {
|
||||||
if (draftVersion.value.loaders.includes(loader)) {
|
if (draftVersion.value.loaders.includes(loader)) {
|
||||||
@@ -62,11 +61,9 @@ const toggleLoader = (loader: string) => {
|
|||||||
} else {
|
} else {
|
||||||
draftVersion.value.loaders = [...draftVersion.value.loaders, loader]
|
draftVersion.value.loaders = [...draftVersion.value.loaders, loader]
|
||||||
}
|
}
|
||||||
setProjectType(projectV2.value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const onClearAll = () => {
|
const onClearAll = () => {
|
||||||
draftVersion.value.loaders = []
|
draftVersion.value.loaders = []
|
||||||
setProjectType(projectV2.value)
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -86,10 +86,6 @@ export interface ManageVersionContextValue {
|
|||||||
file: File,
|
file: File,
|
||||||
project: Labrinth.Projects.v2.Project,
|
project: Labrinth.Projects.v2.Project,
|
||||||
) => Promise<InferredVersionInfo>
|
) => Promise<InferredVersionInfo>
|
||||||
setProjectType: (
|
|
||||||
project: Labrinth.Projects.v2.Project,
|
|
||||||
file?: File | null,
|
|
||||||
) => Promise<Labrinth.Projects.v2.ProjectType | undefined>
|
|
||||||
getProject: (projectId: string) => Promise<Labrinth.Projects.v3.Project>
|
getProject: (projectId: string) => Promise<Labrinth.Projects.v3.Project>
|
||||||
getVersion: (versionId: string) => Promise<Labrinth.Versions.v3.Version>
|
getVersion: (versionId: string) => Promise<Labrinth.Versions.v3.Version>
|
||||||
|
|
||||||
@@ -98,6 +94,41 @@ export interface ManageVersionContextValue {
|
|||||||
handleSaveVersionEdits: () => Promise<void>
|
handleSaveVersionEdits: () => Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PROJECT_TYPE_LOADERS: Record<string, readonly string[]> = {
|
||||||
|
mod: [
|
||||||
|
'fabric',
|
||||||
|
'neoforge',
|
||||||
|
'forge',
|
||||||
|
'quilt',
|
||||||
|
'liteloader',
|
||||||
|
'rift',
|
||||||
|
'ornithe',
|
||||||
|
'nilloader',
|
||||||
|
'risugami',
|
||||||
|
'legacy-fabric',
|
||||||
|
'bta-babric',
|
||||||
|
'babric',
|
||||||
|
'modloader',
|
||||||
|
'java-agent',
|
||||||
|
],
|
||||||
|
shader: ['optifine', 'iris', 'canvas', 'vanilla'],
|
||||||
|
plugin: [
|
||||||
|
'paper',
|
||||||
|
'purpur',
|
||||||
|
'spigot',
|
||||||
|
'bukkit',
|
||||||
|
'sponge',
|
||||||
|
'folia',
|
||||||
|
'bungeecord',
|
||||||
|
'velocity',
|
||||||
|
'waterfall',
|
||||||
|
'geyser',
|
||||||
|
],
|
||||||
|
datapack: ['datapack'],
|
||||||
|
resourcepack: ['minecraft'],
|
||||||
|
modpack: ['mrpack'],
|
||||||
|
} as const
|
||||||
|
|
||||||
export const [injectManageVersionContext, provideManageVersionContext] =
|
export const [injectManageVersionContext, provideManageVersionContext] =
|
||||||
createContext<ManageVersionContextValue>('CreateProjectVersionModal')
|
createContext<ManageVersionContextValue>('CreateProjectVersionModal')
|
||||||
|
|
||||||
@@ -113,80 +144,47 @@ export function createManageVersionContext(
|
|||||||
const filesToAdd = ref<Labrinth.Versions.v3.DraftVersionFile[]>([])
|
const filesToAdd = ref<Labrinth.Versions.v3.DraftVersionFile[]>([])
|
||||||
const existingFilesToDelete = ref<Labrinth.Versions.v3.VersionFileHash['sha1'][]>([])
|
const existingFilesToDelete = ref<Labrinth.Versions.v3.VersionFileHash['sha1'][]>([])
|
||||||
const inferredVersionData = ref<InferredVersionInfo>()
|
const inferredVersionData = ref<InferredVersionInfo>()
|
||||||
const projectType = ref<Labrinth.Projects.v2.ProjectType>()
|
|
||||||
const dependencyProjects = ref<Record<string, Labrinth.Projects.v3.Project>>({})
|
const dependencyProjects = ref<Record<string, Labrinth.Projects.v3.Project>>({})
|
||||||
const dependencyVersions = ref<Record<string, Labrinth.Versions.v3.Version>>({})
|
const dependencyVersions = ref<Record<string, Labrinth.Versions.v3.Version>>({})
|
||||||
const isSubmitting = ref(false)
|
const isSubmitting = ref(false)
|
||||||
|
|
||||||
|
const projectType = computed<Labrinth.Projects.v2.ProjectType>(() => {
|
||||||
|
const primaryFile = filesToAdd.value[0]?.file
|
||||||
|
if (
|
||||||
|
(primaryFile && primaryFile.name.toLowerCase().endsWith('.mrpack')) ||
|
||||||
|
(primaryFile && primaryFile.name.toLowerCase().endsWith('.mrpack-primary'))
|
||||||
|
) {
|
||||||
|
return 'modpack'
|
||||||
|
}
|
||||||
|
|
||||||
|
const loaders = draftVersion.value.loaders || []
|
||||||
|
|
||||||
|
if (loaders.some((loader) => PROJECT_TYPE_LOADERS.modpack.includes(loader))) {
|
||||||
|
return 'modpack'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loaders.some((loader) => PROJECT_TYPE_LOADERS.datapack.includes(loader))) {
|
||||||
|
return 'datapack'
|
||||||
|
}
|
||||||
|
if (loaders.some((loader) => PROJECT_TYPE_LOADERS.resourcepack.includes(loader))) {
|
||||||
|
return 'resourcepack'
|
||||||
|
}
|
||||||
|
if (loaders.some((loader) => PROJECT_TYPE_LOADERS.shader.includes(loader))) {
|
||||||
|
return 'shader'
|
||||||
|
}
|
||||||
|
if (loaders.some((loader) => PROJECT_TYPE_LOADERS.plugin.includes(loader))) {
|
||||||
|
return 'plugin'
|
||||||
|
}
|
||||||
|
if (loaders.some((loader) => PROJECT_TYPE_LOADERS.mod.includes(loader))) {
|
||||||
|
return 'mod'
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'project'
|
||||||
|
})
|
||||||
|
|
||||||
// Computed state
|
// Computed state
|
||||||
const editingVersion = computed(() => Boolean(draftVersion.value.version_id))
|
const editingVersion = computed(() => Boolean(draftVersion.value.version_id))
|
||||||
|
|
||||||
// Helper functions for project type detection
|
|
||||||
// TODO: move to infer.js
|
|
||||||
async function setProjectType(
|
|
||||||
project: Labrinth.Projects.v2.Project,
|
|
||||||
file: File | null = null,
|
|
||||||
): Promise<Labrinth.Projects.v2.ProjectType | undefined> {
|
|
||||||
if (project.project_type && project.project_type !== 'project') {
|
|
||||||
projectType.value = project.project_type
|
|
||||||
return projectType.value
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(file && file.name.toLowerCase().endsWith('.mrpack')) ||
|
|
||||||
(file && file.name.toLowerCase().endsWith('.mrpack-primary'))
|
|
||||||
) {
|
|
||||||
projectType.value = 'modpack'
|
|
||||||
return projectType.value
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
draftVersion.value.loaders?.some((loader) =>
|
|
||||||
[
|
|
||||||
'fabric',
|
|
||||||
'neoforge',
|
|
||||||
'forge',
|
|
||||||
'quilt',
|
|
||||||
'liteloader',
|
|
||||||
'rift',
|
|
||||||
'ornithe',
|
|
||||||
'nilloader',
|
|
||||||
'legacy-fabric',
|
|
||||||
'bta-babric',
|
|
||||||
'babric',
|
|
||||||
'modloader',
|
|
||||||
'java-agent',
|
|
||||||
].includes(loader),
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
projectType.value = 'mod'
|
|
||||||
return projectType.value
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (file) {
|
|
||||||
const jszip = await JSZip.loadAsync(file)
|
|
||||||
|
|
||||||
const hasMcmeta = Object.keys(jszip.files).some(
|
|
||||||
(f) => f.toLowerCase() === 'pack.mcmeta' || f.toLowerCase().endsWith('/pack.mcmeta'),
|
|
||||||
)
|
|
||||||
const hasAssetsDir = Object.keys(jszip.files).some(
|
|
||||||
(f) => f.toLowerCase() === 'assets/' || f.toLowerCase().startsWith('assets/'),
|
|
||||||
)
|
|
||||||
|
|
||||||
if (hasMcmeta && hasAssetsDir) {
|
|
||||||
projectType.value = 'resourcepack'
|
|
||||||
return projectType.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// not a zip
|
|
||||||
}
|
|
||||||
|
|
||||||
projectType.value = undefined
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version management methods
|
// Version management methods
|
||||||
function newDraftVersion(
|
function newDraftVersion(
|
||||||
projectId: string,
|
projectId: string,
|
||||||
@@ -197,7 +195,7 @@ export function createManageVersionContext(
|
|||||||
filesToAdd.value = []
|
filesToAdd.value = []
|
||||||
existingFilesToDelete.value = []
|
existingFilesToDelete.value = []
|
||||||
inferredVersionData.value = undefined
|
inferredVersionData.value = undefined
|
||||||
projectType.value = undefined
|
// projectType.value = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
function setPrimaryFile(index: number) {
|
function setPrimaryFile(index: number) {
|
||||||
@@ -210,6 +208,33 @@ export function createManageVersionContext(
|
|||||||
|
|
||||||
const tags = useGeneratedState()
|
const tags = useGeneratedState()
|
||||||
|
|
||||||
|
const hasFile = (entries: string[], name: string) =>
|
||||||
|
entries.some((f) => f === name || f.endsWith(`/${name}`))
|
||||||
|
|
||||||
|
const hasDir = (entries: string[], dir: string) => entries.some((f) => f.startsWith(`${dir}/`))
|
||||||
|
|
||||||
|
async function checkIsResourcePack(file: File): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const zip = await JSZip.loadAsync(file)
|
||||||
|
const entries = Object.keys(zip.files).map((f) => f.toLowerCase())
|
||||||
|
|
||||||
|
return hasFile(entries, 'pack.mcmeta') && hasDir(entries, 'assets')
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkIsDataPack(file: File): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const zip = await JSZip.loadAsync(file)
|
||||||
|
const entries = Object.keys(zip.files).map((f) => f.toLowerCase())
|
||||||
|
|
||||||
|
return hasFile(entries, 'pack.mcmeta') && hasDir(entries, 'data')
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function setInferredVersionData(
|
async function setInferredVersionData(
|
||||||
file: File,
|
file: File,
|
||||||
project: Labrinth.Projects.v2.Project,
|
project: Labrinth.Projects.v2.Project,
|
||||||
@@ -234,8 +259,21 @@ export function createManageVersionContext(
|
|||||||
console.error('Error fetching versions for environment inference:', error)
|
console.error('Error fetching versions for environment inference:', error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const noLoaders = !inferred.loaders?.length
|
||||||
|
|
||||||
|
if (noLoaders && (await checkIsResourcePack(file))) {
|
||||||
|
inferred.loaders = ['minecraft']
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noLoaders && (await checkIsDataPack(file))) {
|
||||||
|
inferred.loaders = ['datapack']
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noLoaders && projectType.value === 'modpack') {
|
||||||
|
inferred.loaders = ['minecraft']
|
||||||
|
}
|
||||||
|
|
||||||
inferredVersionData.value = inferred
|
inferredVersionData.value = inferred
|
||||||
projectType.value = await setProjectType(project, file)
|
|
||||||
|
|
||||||
return inferred
|
return inferred
|
||||||
}
|
}
|
||||||
@@ -423,7 +461,6 @@ export function createManageVersionContext(
|
|||||||
newDraftVersion,
|
newDraftVersion,
|
||||||
setPrimaryFile,
|
setPrimaryFile,
|
||||||
setInferredVersionData,
|
setInferredVersionData,
|
||||||
setProjectType,
|
|
||||||
getProject,
|
getProject,
|
||||||
getVersion,
|
getVersion,
|
||||||
handleCreateVersion,
|
handleCreateVersion,
|
||||||
|
|||||||
Reference in New Issue
Block a user