mirror of
https://github.com/modrinth/code.git
synced 2026-08-25 00:55:25 +00:00
fix: breadcrumb issue on browse content via server panel (#6971)
fix: breadcrumb issue on browse/navigation bar Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com>
This commit is contained in:
@@ -1547,8 +1547,10 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
|||||||
<NavButton
|
<NavButton
|
||||||
v-tooltip.right="formatMessage(commonMessages.discoverContentLabel)"
|
v-tooltip.right="formatMessage(commonMessages.discoverContentLabel)"
|
||||||
to="/browse/modpack"
|
to="/browse/modpack"
|
||||||
:is-primary="() => route.path.startsWith('/browse') && !route.query.i"
|
:is-primary="() => route.path.startsWith('/browse') && !route.query.i && !route.query.sid"
|
||||||
:is-subpage="(route) => route.path.startsWith('/project') && !route.query.i"
|
:is-subpage="
|
||||||
|
(route) => route.path.startsWith('/project') && !route.query.i && !route.query.sid
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<CompassIcon />
|
<CompassIcon />
|
||||||
</NavButton>
|
</NavButton>
|
||||||
@@ -1572,7 +1574,11 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
|||||||
v-tooltip.right="formatMessage(messages.modrinthHosting)"
|
v-tooltip.right="formatMessage(messages.modrinthHosting)"
|
||||||
to="/hosting/manage"
|
to="/hosting/manage"
|
||||||
:is-primary="(r) => r.path === '/hosting/manage' || r.path === '/hosting/manage/'"
|
:is-primary="(r) => r.path === '/hosting/manage' || r.path === '/hosting/manage/'"
|
||||||
:is-subpage="(r) => r.path.startsWith('/hosting/manage/') && r.path !== '/hosting/manage/'"
|
:is-subpage="
|
||||||
|
(r) =>
|
||||||
|
(r.path.startsWith('/hosting/manage/') && r.path !== '/hosting/manage/') ||
|
||||||
|
((r.path.startsWith('/browse') || r.path.startsWith('/project')) && r.query.sid)
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<ServerStackIcon />
|
<ServerStackIcon />
|
||||||
</NavButton>
|
</NavButton>
|
||||||
|
|||||||
@@ -56,11 +56,7 @@ import {
|
|||||||
instanceKeys,
|
instanceKeys,
|
||||||
instanceLinkedProjectQueryOptions,
|
instanceLinkedProjectQueryOptions,
|
||||||
} from '@/pages/instance/query-options'
|
} from '@/pages/instance/query-options'
|
||||||
import {
|
import { type BreadcrumbDefinition, injectBreadcrumbManager } from '@/providers/breadcrumbs'
|
||||||
type BreadcrumbDefinition,
|
|
||||||
useBreadcrumb,
|
|
||||||
useRootBreadcrumb,
|
|
||||||
} from '@/providers/breadcrumbs'
|
|
||||||
import { injectContentInstall } from '@/providers/content-install'
|
import { injectContentInstall } from '@/providers/content-install'
|
||||||
import { injectServerInstall } from '@/providers/server-install'
|
import { injectServerInstall } from '@/providers/server-install'
|
||||||
import {
|
import {
|
||||||
@@ -177,13 +173,13 @@ const isServerInstance = computed(
|
|||||||
() => linkedInstanceProjectQuery.data.value?.minecraft_server != null,
|
() => linkedInstanceProjectQuery.data.value?.minecraft_server != null,
|
||||||
)
|
)
|
||||||
|
|
||||||
const instanceBreadcrumb = route.query.i
|
const breadcrumbManager = injectBreadcrumbManager()
|
||||||
? useBreadcrumb({
|
const instanceBreadcrumbDefinition = {
|
||||||
slot: 'instance',
|
slot: 'instance',
|
||||||
id: () => `instance:${String(displayedBrowseRoute.value.query.i ?? '')}`,
|
id: () => `instance:${String(displayedBrowseRoute.value.query.i ?? '')}`,
|
||||||
label: () => instance.value?.name ?? formatMessage(commonMessages.loadingLabel),
|
label: () => instance.value?.name ?? formatMessage(commonMessages.loadingLabel),
|
||||||
visual: () => ({
|
visual: () => ({
|
||||||
type: 'image',
|
type: 'image' as const,
|
||||||
src: instance.value?.icon_path ? convertFileSrc(instance.value.icon_path) : undefined,
|
src: instance.value?.icon_path ? convertFileSrc(instance.value.icon_path) : undefined,
|
||||||
alt: instance.value?.name,
|
alt: instance.value?.name,
|
||||||
tintBy: String(displayedBrowseRoute.value.query.i ?? ''),
|
tintBy: String(displayedBrowseRoute.value.query.i ?? ''),
|
||||||
@@ -196,26 +192,27 @@ const instanceBreadcrumb = route.query.i
|
|||||||
? `${instancePath}/worlds`
|
? `${instancePath}/worlds`
|
||||||
: instancePath
|
: instancePath
|
||||||
},
|
},
|
||||||
})
|
} satisfies BreadcrumbDefinition
|
||||||
: undefined
|
const serversBreadcrumbDefinition = {
|
||||||
|
slot: 'root',
|
||||||
|
id: 'servers',
|
||||||
|
label: () => formatMessage(commonMessages.serversLabel),
|
||||||
|
to: '/hosting/manage/',
|
||||||
|
visual: { type: 'icon', component: ServerStackIcon },
|
||||||
|
} satisfies BreadcrumbDefinition
|
||||||
const serverBreadcrumbTo = ref(serverBackUrl.value)
|
const serverBreadcrumbTo = ref(serverBackUrl.value)
|
||||||
watch(serverBackUrl, (value) => {
|
watch(serverBackUrl, (value) => {
|
||||||
if (route.path.startsWith('/browse/')) {
|
if (route.path.startsWith('/browse/')) {
|
||||||
serverBreadcrumbTo.value = value
|
serverBreadcrumbTo.value = value
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const serverBreadcrumb =
|
const serverBreadcrumbDefinition = {
|
||||||
!instanceBreadcrumb && serverIdQuery.value
|
|
||||||
? useBreadcrumb({
|
|
||||||
slot: 'server',
|
slot: 'server',
|
||||||
id: () => `server:${String(displayedBrowseRoute.value.query.sid ?? '')}`,
|
id: () => `server:${String(displayedBrowseRoute.value.query.sid ?? '')}`,
|
||||||
label: () =>
|
label: () => serverContextServerData.value?.name ?? formatMessage(commonMessages.loadingLabel),
|
||||||
serverContextServerData.value?.name ?? formatMessage(commonMessages.loadingLabel),
|
|
||||||
visual: { type: 'icon', component: ServerStackIcon },
|
visual: { type: 'icon', component: ServerStackIcon },
|
||||||
to: serverBreadcrumbTo,
|
to: serverBreadcrumbTo,
|
||||||
})
|
} satisfies BreadcrumbDefinition
|
||||||
: undefined
|
|
||||||
const breadcrumbParent = instanceBreadcrumb ?? serverBreadcrumb
|
|
||||||
const breadcrumbDefinition = {
|
const breadcrumbDefinition = {
|
||||||
slot: 'browse',
|
slot: 'browse',
|
||||||
id: () =>
|
id: () =>
|
||||||
@@ -228,9 +225,27 @@ const breadcrumbDefinition = {
|
|||||||
to: () => displayedBrowseRoute.value.fullPath,
|
to: () => displayedBrowseRoute.value.fullPath,
|
||||||
visual: { type: 'icon', component: CompassIcon },
|
visual: { type: 'icon', component: CompassIcon },
|
||||||
} satisfies BreadcrumbDefinition
|
} satisfies BreadcrumbDefinition
|
||||||
const browseBreadcrumb = breadcrumbParent
|
|
||||||
? useBreadcrumb(breadcrumbDefinition, { parent: breadcrumbParent })
|
function syncBreadcrumbs() {
|
||||||
: useRootBreadcrumb(breadcrumbDefinition)
|
if (displayedBrowseRoute.value.query.i) {
|
||||||
|
const instanceBreadcrumb = breadcrumbManager.reset(instanceBreadcrumbDefinition)
|
||||||
|
breadcrumbManager.push(breadcrumbDefinition, { parent: instanceBreadcrumb })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayedBrowseRoute.value.query.sid) {
|
||||||
|
const serversBreadcrumb = breadcrumbManager.reset(serversBreadcrumbDefinition)
|
||||||
|
const serverBreadcrumb = breadcrumbManager.push(serverBreadcrumbDefinition, {
|
||||||
|
parent: serversBreadcrumb,
|
||||||
|
})
|
||||||
|
breadcrumbManager.push(breadcrumbDefinition, { parent: serverBreadcrumb })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
breadcrumbManager.reset(breadcrumbDefinition)
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(displayedBrowseRoute, syncBreadcrumbs, { immediate: true, flush: 'sync' })
|
||||||
|
|
||||||
debugLog('fetching tags (categories, loaders, gameVersions)')
|
debugLog('fetching tags (categories, loaders, gameVersions)')
|
||||||
const [categories, loaders, availableGameVersions] = await Promise.all([
|
const [categories, loaders, availableGameVersions] = await Promise.all([
|
||||||
@@ -595,6 +610,7 @@ function resetInstanceContext() {
|
|||||||
newlyInstalled.value = []
|
newlyInstalled.value = []
|
||||||
hiddenInstanceProjectIds.value = new Set()
|
hiddenInstanceProjectIds.value = new Set()
|
||||||
hiddenInstanceProjectIdsInitialized.value = false
|
hiddenInstanceProjectIdsInitialized.value = false
|
||||||
|
isServerInstance.value = false
|
||||||
browseBreadcrumb.reset()
|
browseBreadcrumb.reset()
|
||||||
void refreshInstalledProjectIds()
|
void refreshInstalledProjectIds()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,7 +222,29 @@ export function createServerInstallContent(opts: {
|
|||||||
const isSetupServerContext = computed(() => !!serverIdQuery.value && !!serverFlowFrom.value)
|
const isSetupServerContext = computed(() => !!serverIdQuery.value && !!serverFlowFrom.value)
|
||||||
|
|
||||||
const serverContextWorldId = ref<string | null>(worldIdQuery.value)
|
const serverContextWorldId = ref<string | null>(worldIdQuery.value)
|
||||||
const serverContextServerData = ref<Archon.Servers.v0.Server | null>(null)
|
|
||||||
|
function getCachedServer(serverId: string): Archon.Servers.v0.Server | null {
|
||||||
|
return (
|
||||||
|
queryClient.getQueryData<Archon.Servers.v0.Server>(['servers', 'detail', serverId]) ??
|
||||||
|
queryClient
|
||||||
|
.getQueryData<Archon.Servers.v0.ServerGetResponse>(['servers'])
|
||||||
|
?.servers.find((server) => server.server_id === serverId) ??
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureServer(serverId: string): Promise<Archon.Servers.v0.Server> {
|
||||||
|
return queryClient.ensureQueryData({
|
||||||
|
queryKey: ['servers', 'detail', serverId],
|
||||||
|
queryFn: () => client.archon.servers_v0.get(serverId),
|
||||||
|
staleTime: 30_000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialServerId = serverIdQuery.value
|
||||||
|
const serverContextServerData = ref<Archon.Servers.v0.Server | null>(
|
||||||
|
initialServerId ? getCachedServer(initialServerId) : null,
|
||||||
|
)
|
||||||
const serverContentProjectIds = ref<Set<string>>(new Set())
|
const serverContentProjectIds = ref<Set<string>>(new Set())
|
||||||
const serverContentInstallKeys = ref<Set<string>>(new Set())
|
const serverContentInstallKeys = ref<Set<string>>(new Set())
|
||||||
const queuedServerInstalls = ref<Map<string, BrowseInstallPlan<InstallableSearchResult>>>(
|
const queuedServerInstalls = ref<Map<string, BrowseInstallPlan<InstallableSearchResult>>>(
|
||||||
@@ -277,6 +299,9 @@ export function createServerInstallContent(opts: {
|
|||||||
async function refreshServerInstalledContent(serverId: string, worldId: string) {
|
async function refreshServerInstalledContent(serverId: string, worldId: string) {
|
||||||
try {
|
try {
|
||||||
const content = await client.archon.content_v1.getAddons(serverId, worldId)
|
const content = await client.archon.content_v1.getAddons(serverId, worldId)
|
||||||
|
if (serverIdQuery.value !== serverId || effectiveServerWorldId.value !== worldId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const ids = new Set(
|
const ids = new Set(
|
||||||
(content.addons ?? [])
|
(content.addons ?? [])
|
||||||
.map((addon) => addon.project_id)
|
.map((addon) => addon.project_id)
|
||||||
@@ -297,14 +322,20 @@ export function createServerInstallContent(opts: {
|
|||||||
if (!sid) return
|
if (!sid) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
serverContextServerData.value = await client.archon.servers_v0.get(sid)
|
const server = await ensureServer(sid)
|
||||||
|
if (serverIdQuery.value === sid) {
|
||||||
|
serverContextServerData.value = server
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
handleError(err as Error)
|
handleError(err as Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (serverIdQuery.value !== sid) return
|
||||||
|
|
||||||
let resolvedWorldId = effectiveServerWorldId.value
|
let resolvedWorldId = effectiveServerWorldId.value
|
||||||
if (!resolvedWorldId) {
|
if (!resolvedWorldId) {
|
||||||
resolvedWorldId = await resolveServerContextWorldId(sid)
|
resolvedWorldId = await resolveServerContextWorldId(sid)
|
||||||
|
if (serverIdQuery.value !== sid) return
|
||||||
if (resolvedWorldId) {
|
if (resolvedWorldId) {
|
||||||
serverContextWorldId.value = resolvedWorldId
|
serverContextWorldId.value = resolvedWorldId
|
||||||
}
|
}
|
||||||
@@ -319,6 +350,7 @@ export function createServerInstallContent(opts: {
|
|||||||
function watchServerContextChanges() {
|
function watchServerContextChanges() {
|
||||||
watch([serverIdQuery, effectiveServerWorldId], async ([sid, wid], [prevSid, prevWid]) => {
|
watch([serverIdQuery, effectiveServerWorldId], async ([sid, wid], [prevSid, prevWid]) => {
|
||||||
if (!sid) {
|
if (!sid) {
|
||||||
|
serverContextWorldId.value = null
|
||||||
serverContextServerData.value = null
|
serverContextServerData.value = null
|
||||||
serverContentProjectIds.value = new Set()
|
serverContentProjectIds.value = new Set()
|
||||||
serverContentInstallKeys.value = new Set()
|
serverContentInstallKeys.value = new Set()
|
||||||
@@ -330,8 +362,12 @@ export function createServerInstallContent(opts: {
|
|||||||
serverContentProjectIds.value = new Set()
|
serverContentProjectIds.value = new Set()
|
||||||
serverContentInstallKeys.value = new Set()
|
serverContentInstallKeys.value = new Set()
|
||||||
queuedServerInstalls.value = readStoredServerInstallQueue(sid, wid)
|
queuedServerInstalls.value = readStoredServerInstallQueue(sid, wid)
|
||||||
|
serverContextServerData.value = getCachedServer(sid)
|
||||||
try {
|
try {
|
||||||
serverContextServerData.value = await client.archon.servers_v0.get(sid)
|
const server = await ensureServer(sid)
|
||||||
|
if (serverIdQuery.value === sid) {
|
||||||
|
serverContextServerData.value = server
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
handleError(err as Error)
|
handleError(err as Error)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user