diff --git a/apps/frontend/src/components/ui/ProjectDownloadModal/index.vue b/apps/frontend/src/components/ui/ProjectDownloadModal/index.vue index 7b23b13db6..472bf8bb84 100644 --- a/apps/frontend/src/components/ui/ProjectDownloadModal/index.vue +++ b/apps/frontend/src/components/ui/ProjectDownloadModal/index.vue @@ -89,7 +89,7 @@ import { } from '@modrinth/ui' import type { DisplayProjectType } from '@modrinth/utils' import { useQuery } from '@tanstack/vue-query' -import { computed, ref, watch } from 'vue' +import { computed, nextTick, ref, watch } from 'vue' import { navigateTo } from '#app' import { saveFeatureFlags } from '~/composables/featureFlags.ts' @@ -118,11 +118,13 @@ type NewModalRef = { const props = withDefaults( defineProps<{ - projectId: string + projectId?: string downloadReason?: CdnDownloadReason + useRouteHash?: boolean }>(), { downloadReason: 'standalone', + useRouteHash: true, }, ) @@ -140,19 +142,20 @@ const debug = useDebugLogger('DownloadModal') const modal = ref(null) const modalOpen = ref(false) +const showProjectId = ref(null) const downloadProjectResetKey = ref(0) -const projectDownloadSelection = ref({ - currentGameVersion: null, - currentPlatform: null, - selectedVersion: null, - selectedPrimaryFile: null, -}) +const projectDownloadSelection = ref(getDefaultProjectDownloadSelection()) -const routeProjectId = computed(() => props.projectId) +const routeProjectId = computed(() => showProjectId.value ?? props.projectId ?? null) -const { data: projectRaw, error: projectV2Error } = useQuery({ +const { + data: projectRaw, + error: projectV2Error, + refetch: refetchProject, +} = useQuery({ queryKey: computed(() => ['project', 'v2', routeProjectId.value]), - queryFn: () => client.labrinth.projects_v2.get(routeProjectId.value), + queryFn: () => client.labrinth.projects_v2.get(routeProjectId.value!), + enabled: computed(() => !!routeProjectId.value), staleTime: STALE_TIME, }) @@ -320,23 +323,33 @@ function onShow() { modalOpen.value = true debug('on-show fired') versionsEnabled.value = true - navigateTo({ query: route.query, hash: '#download' }, { replace: true }) + if (props.useRouteHash && !showProjectId.value) { + navigateTo({ query: route.query, hash: '#download' }, { replace: true }) + } } function onHide() { + const hadShowProjectId = !!showProjectId.value modalOpen.value = false - navigateTo({ query: route.query, hash: '' }, { replace: true }) + showProjectId.value = null + if (props.useRouteHash && !hadShowProjectId) { + navigateTo({ query: route.query, hash: '' }, { replace: true }) + } } -function show(event?: MouseEvent) { +async function show(event?: MouseEvent, projectId?: string): Promise { if (!modal.value || modalOpen.value) return + showProjectId.value = projectId ?? null + await nextTick() + if (!(await loadProjectForModal(!!projectId))) return modalOpen.value = true modal.value.show(event) } -function hide() { +async function hide() { if (!modal.value || !modalOpen.value) return modal.value?.hide() + await nextTick() downloadProjectResetKey.value += 1 } @@ -344,17 +357,43 @@ function onDownload() { emit('download') } +function getDefaultProjectDownloadSelection(): ProjectDownloadSelection { + return { + currentGameVersion: null, + currentPlatform: null, + selectedVersion: null, + selectedPrimaryFile: null, + } +} + +async function loadProjectForModal(forceRefetch: boolean) { + if (!routeProjectId.value) return false + if (!forceRefetch && projectRaw.value) return true + + const { data } = await refetchProject() + return !!data +} + function openFromHash() { - if (!modal.value || modalOpen.value || route.hash !== '#download') return + if ( + !props.useRouteHash || + !modal.value || + modalOpen.value || + showProjectId.value || + route.hash !== '#download' + ) { + return + } debug('hash #download watch fired, opening modal') show() } if ( - route.hash === '#download' || - route.query.version !== undefined || - route.query.loader !== undefined + props.useRouteHash && + (route.hash === '#download' || + route.query.version !== undefined || + route.query.loader !== undefined) ) { debug('eager loadVersions from setup', { hash: route.hash, @@ -367,6 +406,10 @@ if ( watch(modal, openFromHash) watch(() => route.hash, openFromHash) +watch(routeProjectId, () => { + projectDownloadSelection.value = getDefaultProjectDownloadSelection() + downloadProjectResetKey.value += 1 +}) defineExpose({ show, hide }) diff --git a/apps/frontend/src/pages/[type]/[project]/version/[version].vue b/apps/frontend/src/pages/[type]/[project]/version/[version].vue index 6fdb5f8c6a..27b655aabe 100644 --- a/apps/frontend/src/pages/[type]/[project]/version/[version].vue +++ b/apps/frontend/src/pages/[type]/[project]/version/[version].vue @@ -80,6 +80,12 @@ +
- - + @@ -519,6 +525,7 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query' import { onServerPrefetch } from 'vue' import CreateProjectVersionModal from '~/components/ui/create-project-version/CreateProjectVersionModal.vue' +import ProjectDownloadModal from '~/components/ui/ProjectDownloadModal/index.vue' import { getSignInRouteObj } from '~/composables/auth.ts' import { projectQueryOptions, STALE_TIME } from '~/composables/queries/project' import { versionQueryOptions } from '~/composables/queries/version' @@ -774,6 +781,7 @@ useSeoMeta({ const editModal = useTemplateRef('editModal') const confirmModal = useTemplateRef('confirmModal') const packageModal = useTemplateRef('packageModal') +const dependencyDownloadModal = useTemplateRef('dependencyDownloadModal') const packageLoaders = ref(['forge', 'fabric', 'quilt', 'neoforge']) const packageLoaderOptions = [ @@ -796,6 +804,10 @@ function handleOpenEditVersionModal(versionId: string, projectId: string, stageI editModal.value?.openEditVersionModal(versionId, projectId, stageId) } +function openDependencyDownloadModal(projectId: string, event: MouseEvent) { + dependencyDownloadModal.value?.show(event, projectId) +} + const deleteVersionMutation = useMutation({ mutationFn: () => client.labrinth.versions_v3.deleteVersion(version.value!.id), onSuccess: async () => { @@ -1065,7 +1077,11 @@ function getDependencyVersion(dependency: Labrinth.Versions.v3.Dependency) { return undefined } - return projectOnlyDependencyVersions.value?.[dependency.project_id] + return ( + (Object.keys(projectOnlyDependencyVersions.value || {}).length === 1 && + projectOnlyDependencyVersions.value?.[dependency.project_id]) || + undefined + ) } function getDependencyPrimaryFile(version?: Labrinth.Versions.v2.Version) {