diff --git a/apps/frontend/src/components/ui/ProjectDownloadModal.vue b/apps/frontend/src/components/ui/ProjectDownloadModal.vue
index 028d4450b8..acaf391d29 100644
--- a/apps/frontend/src/components/ui/ProjectDownloadModal.vue
+++ b/apps/frontend/src/components/ui/ProjectDownloadModal.vue
@@ -17,7 +17,7 @@
>
@@ -83,13 +83,12 @@
"
class="flex w-full items-center justify-between gap-2"
:class="{
- 'text-brand-red': !possibleGameVersions.includes(item.value),
+ 'text-brand-red opacity-40': !possibleGameVersions.includes(item.value),
'text-green': isSelected,
'text-primary': possibleGameVersions.includes(item.value) && !isSelected,
}"
>
{{ item.label }}
-
@@ -128,13 +127,12 @@
"
class="flex w-full items-center justify-between gap-2"
:class="{
- 'text-brand-red': !possiblePlatforms.includes(item.value),
+ 'text-brand-red opacity-40': !possiblePlatforms.includes(item.value),
'text-green': isSelected,
'text-primary': possiblePlatforms.includes(item.value) && !isSelected,
}"
>
{{ item.label }}
-
@@ -157,13 +155,14 @@
@@ -196,12 +195,8 @@
:key="dependency.key"
class="flex flex-col gap-1.5"
>
-
-
+
+ {{ dependency.name }}
+
+
{{ dependency.name }}
{{ dependency.typeLabel }}
-
-
+
+
+
+
+
+
@@ -270,7 +299,7 @@
selectedDependencyVersionIds.value.length > 0),
})
+const fallbackDependencyProjectIds = computed(() => {
+ if (!selectedVersion.value) return []
+
+ return [
+ ...new Set(
+ selectedVersion.value.dependencies
+ .filter(
+ (dependency) =>
+ ['required', 'optional'].includes(dependency.dependency_type) &&
+ !dependency.version_id &&
+ dependency.project_id,
+ )
+ .map((dependency) => dependency.project_id),
+ ),
+ ]
+})
+
+const { data: fallbackDependencyVersions } = useQuery({
+ queryKey: computed(() => [
+ 'project-download-modal',
+ 'fallback-versions',
+ fallbackDependencyProjectIds.value,
+ ]),
+ queryFn: async () =>
+ Promise.all(
+ fallbackDependencyProjectIds.value.map(async (projectId) => {
+ const versions = await client.labrinth.versions_v3.getProjectVersions(projectId, {
+ include_changelog: false,
+ limit: 1,
+ })
+
+ return versions[0]
+ }),
+ ),
+ enabled: computed(() => fallbackDependencyProjectIds.value.length > 0),
+})
+
const subDependencyVersionIds = computed(() => {
const ids = new Set()
- for (const version of dependencyVersions.value || []) {
+ for (const version of [
+ ...(dependencyVersions.value || []),
+ ...(fallbackDependencyVersions.value || []),
+ ]) {
+ if (!version) continue
for (const dependency of version.dependencies || []) {
if (dependency.version_id) ids.add(dependency.version_id)
}
@@ -575,17 +645,74 @@ const { data: subDependencyVersions } = useQuery({
enabled: computed(() => subDependencyVersionIds.value.length > 0),
})
+const fallbackSubDependencyProjectIds = computed(() => {
+ const ids = new Set()
+
+ for (const version of [
+ ...(dependencyVersions.value || []),
+ ...(fallbackDependencyVersions.value || []),
+ ]) {
+ if (!version) continue
+ for (const dependency of version.dependencies || []) {
+ if (
+ ['required', 'optional'].includes(dependency.dependency_type) &&
+ !dependency.version_id &&
+ dependency.project_id
+ ) {
+ ids.add(dependency.project_id)
+ }
+ }
+ }
+
+ return [...ids]
+})
+
+const { data: fallbackSubDependencyVersions } = useQuery({
+ queryKey: computed(() => [
+ 'project-download-modal',
+ 'fallback-sub-versions',
+ fallbackSubDependencyProjectIds.value,
+ ]),
+ queryFn: async () =>
+ Promise.all(
+ fallbackSubDependencyProjectIds.value.map(async (projectId) => {
+ const versions = await client.labrinth.versions_v3.getProjectVersions(projectId, {
+ include_changelog: false,
+ limit: 1,
+ })
+
+ return versions[0]
+ }),
+ ),
+ enabled: computed(() => fallbackSubDependencyProjectIds.value.length > 0),
+})
+
const dependencyVersionById = computed(() => {
const map = new Map()
for (const version of [
...(dependencyVersions.value || []),
...(subDependencyVersions.value || []),
+ ...(fallbackDependencyVersions.value || []),
+ ...(fallbackSubDependencyVersions.value || []),
]) {
+ if (!version) continue
map.set(version.id, version)
}
return map
})
+const fallbackDependencyVersionByProjectId = computed(() => {
+ const map = new Map()
+ for (const version of [
+ ...(fallbackDependencyVersions.value || []),
+ ...(fallbackSubDependencyVersions.value || []),
+ ]) {
+ if (!version) continue
+ map.set(version.project_id, version)
+ }
+ return map
+})
+
const selectedDependencyProjectIds = computed(() => {
const ids = new Set()
@@ -597,7 +724,11 @@ const selectedDependencyProjectIds = computed(() => {
if (version?.project_id) ids.add(version.project_id)
}
- for (const version of dependencyVersions.value || []) {
+ for (const version of [
+ ...(dependencyVersions.value || []),
+ ...(fallbackDependencyVersions.value || []),
+ ]) {
+ if (!version) continue
for (const dependency of version.dependencies || []) {
if (dependency.project_id) ids.add(dependency.project_id)
const dependencyVersion = dependency.version_id
@@ -607,6 +738,13 @@ const selectedDependencyProjectIds = computed(() => {
}
}
+ for (const version of [
+ ...(fallbackDependencyVersions.value || []),
+ ...(fallbackSubDependencyVersions.value || []),
+ ]) {
+ if (version?.project_id) ids.add(version.project_id)
+ }
+
return [...ids]
})
@@ -633,6 +771,10 @@ const dependencyRows = computed(() => {
return selectedVersion.value.dependencies
.filter((dependency) => ['required', 'optional'].includes(dependency.dependency_type))
+ .sort(
+ (a, b) =>
+ dependencyTypeSortOrder(a.dependency_type) - dependencyTypeSortOrder(b.dependency_type),
+ )
.map((dependency) => createDependencyRow(dependency))
})
@@ -722,6 +864,15 @@ function dependencyTypeLabel(type) {
)
}
+function dependencyTypeSortOrder(type) {
+ return (
+ {
+ required: 0,
+ optional: 1,
+ }[type] ?? 2
+ )
+}
+
function fileTypeLabel(type) {
return (
{
@@ -737,9 +888,16 @@ function primaryFileForVersion(version) {
}
function createDependencyRow(dependency, includeSubDependencies = true) {
- const version = dependency.version_id
+ const explicitVersion = dependency.version_id
? dependencyVersionById.value.get(dependency.version_id)
: null
+ // todo: need algorithm for picking version.
+ // try to match same game version and loader. and if cannot, then disable button and have tooltip saying cannot find any compatible versions to download.
+ const version =
+ explicitVersion ||
+ (dependency.project_id
+ ? fallbackDependencyVersionByProjectId.value.get(dependency.project_id)
+ : null)
const projectId = dependency.project_id || version?.project_id
const project = projectId ? dependencyProjectById.value.get(projectId) : null
const primaryFile = primaryFileForVersion(version)
@@ -756,31 +914,26 @@ function createDependencyRow(dependency, includeSubDependencies = true) {
key: `${dependency.dependency_type}-${dependency.version_id ?? dependency.project_id ?? dependency.file_name ?? name}`,
name,
icon: project?.icon_url,
- href: primaryFile
- ? decorateModalDownloadUrl(primaryFile.url)
- : project
- ? `/${project.project_type}/${project.slug || project.id}`
- : undefined,
+ projectHref: project ? `/${project.project_type}/${project.slug || project.id}` : undefined,
+ downloadHref: primaryFile ? getDownloadUrl(primaryFile.url) : undefined,
filename: primaryFile?.filename,
- downloadsFile: !!primaryFile,
typeLabel: dependencyTypeLabel(dependency.dependency_type),
subDependencies: includeSubDependencies
? (version?.dependencies || [])
.filter((subDependency) =>
['required', 'optional'].includes(subDependency.dependency_type),
)
+ .sort(
+ (a, b) =>
+ dependencyTypeSortOrder(a.dependency_type) -
+ dependencyTypeSortOrder(b.dependency_type),
+ )
.map((subDependency) => createDependencyRow(subDependency, false))
: [],
}
}
-function onDependencyRowClick(row, event) {
- if (row.downloadsFile) {
- onDownload(event)
- }
-}
-
-function decorateModalDownloadUrl(url) {
+function getDownloadUrl(url) {
return createProjectDownloadUrl(url, {
reason: props.downloadReason,
gameVersion: currentGameVersion.value ?? undefined,
@@ -854,11 +1007,8 @@ function hide(event) {
showAllVersions.value = false
}
-function onDownload(event) {
+function onDownload() {
emit('download')
- setTimeout(() => {
- hide(event)
- }, 400)
}
function onVersionNavigate(url) {