Skip to content

Commit c760260

Browse files
authored
fix: use localstorage for sync state during install (#6057)
* fix: use localstorage for sync state during install * fix: lint
1 parent 07f9e3a commit c760260

9 files changed

Lines changed: 1262 additions & 757 deletions

File tree

apps/app-frontend/src/providers/setup/server-install-content.ts

Lines changed: 58 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@ import {
55
type BrowseSelectedProject,
66
createContext,
77
type CreationFlowContextValue,
8-
flushInstallQueue,
8+
flushStoredServerAddonInstallQueue,
9+
getStoredServerAddonInstallQueue,
910
injectModrinthClient,
1011
injectNotificationManager,
1112
type PendingServerContentInstall,
1213
type PendingServerContentInstallType,
1314
readPendingServerContentInstalls,
15+
readStoredServerInstallQueue,
1416
removePendingServerContentInstall,
1517
writePendingServerContentInstallBaseline,
18+
writeStoredServerInstallQueue,
1619
} from '@modrinth/ui'
1720
import { computed, type ComputedRef, nextTick, type Ref, ref, watch } from 'vue'
1821
import { useRoute, useRouter } from 'vue-router'
@@ -89,37 +92,6 @@ function readQueryString(value: unknown): string | null {
8992
return typeof value === 'string' && value.length > 0 ? value : null
9093
}
9194

92-
function getQueueStorageKey(serverId: string | null, worldId: string | null) {
93-
if (!serverId || !worldId) return null
94-
return `server-install-queue:${serverId}:${worldId}`
95-
}
96-
97-
function readStoredQueue(serverId: string | null, worldId: string | null) {
98-
const key = getQueueStorageKey(serverId, worldId)
99-
if (!key) return new Map<string, BrowseInstallPlan<InstallableSearchResult>>()
100-
try {
101-
const raw = localStorage.getItem(key)
102-
if (!raw) return new Map<string, BrowseInstallPlan<InstallableSearchResult>>()
103-
return new Map<string, BrowseInstallPlan<InstallableSearchResult>>(JSON.parse(raw))
104-
} catch {
105-
return new Map<string, BrowseInstallPlan<InstallableSearchResult>>()
106-
}
107-
}
108-
109-
function writeStoredQueue(
110-
serverId: string | null,
111-
worldId: string | null,
112-
plans: Map<string, BrowseInstallPlan<InstallableSearchResult>>,
113-
) {
114-
const key = getQueueStorageKey(serverId, worldId)
115-
if (!key) return
116-
if (plans.size === 0) {
117-
localStorage.removeItem(key)
118-
return
119-
}
120-
localStorage.setItem(key, JSON.stringify(Array.from(plans.entries())))
121-
}
122-
12395
function getQueuedInstallOwnerFallback(project: InstallableSearchResult) {
12496
if (project.organization) {
12597
const ownerId = project.organization_id ?? project.organization
@@ -235,7 +207,7 @@ export function createServerInstallContent(opts: {
235207
const route = useRoute()
236208
const router = useRouter()
237209
const client = injectModrinthClient()
238-
const { addNotification, handleError } = injectNotificationManager()
210+
const { handleError } = injectNotificationManager()
239211

240212
const serverIdQuery = computed(() => readQueryString(route.query.sid))
241213
const worldIdQuery = computed(() => readQueryString(route.query.wid))
@@ -340,7 +312,7 @@ export function createServerInstallContent(opts: {
340312
}
341313

342314
if (resolvedWorldId) {
343-
queuedServerInstalls.value = readStoredQueue(sid, resolvedWorldId)
315+
queuedServerInstalls.value = readStoredServerInstallQueue(sid, resolvedWorldId)
344316
await refreshServerInstalledContent(sid, resolvedWorldId)
345317
}
346318
}
@@ -358,7 +330,7 @@ export function createServerInstallContent(opts: {
358330
if (sid !== prevSid) {
359331
serverContentProjectIds.value = new Set()
360332
serverContentInstallKeys.value = new Set()
361-
queuedServerInstalls.value = readStoredQueue(sid, wid)
333+
queuedServerInstalls.value = readStoredServerInstallQueue(sid, wid)
362334
try {
363335
serverContextServerData.value = await client.archon.servers_v0.get(sid)
364336
} catch (err) {
@@ -367,7 +339,7 @@ export function createServerInstallContent(opts: {
367339
}
368340

369341
if (wid !== prevWid) {
370-
queuedServerInstalls.value = readStoredQueue(sid, wid)
342+
queuedServerInstalls.value = readStoredServerInstallQueue(sid, wid)
371343
}
372344

373345
if (wid && (sid !== prevSid || wid !== prevWid)) {
@@ -432,62 +404,75 @@ export function createServerInstallContent(opts: {
432404
setQueuedServerInstallPlans(nextPlans)
433405
}
434406

407+
function setStoredServerInstallPlans(
408+
serverId: string,
409+
worldId: string,
410+
plans: Map<string, BrowseInstallPlan<InstallableSearchResult>>,
411+
) {
412+
if (serverId === serverIdQuery.value && worldId === effectiveServerWorldId.value) {
413+
queuedServerInstalls.value = plans
414+
}
415+
writeStoredServerInstallQueue(serverId, worldId, plans)
416+
}
417+
435418
async function flushQueuedServerInstalls(
436419
serverId: string | null = serverIdQuery.value,
437420
worldId: string | null = effectiveServerWorldId.value,
438421
) {
439-
if (queuedServerInstalls.value.size === 0) return true
440422
if (isInstallingQueuedServerInstalls.value) return false
441423

442424
if (!serverId || !worldId) {
443425
handleError(new Error('No server world is available for install.'))
444426
return false
445427
}
446428

447-
const installedProjectIds = new Set<string>()
429+
const queuedPlans = getStoredServerAddonInstallQueue<InstallableSearchResult>(serverId, worldId)
430+
if (queuedPlans.size === 0) return true
431+
448432
isInstallingQueuedServerInstalls.value = true
449433
queuedInstallProgress.value = {
450434
completed: 0,
451-
total: queuedServerInstalls.value.size,
435+
total: queuedPlans.size,
452436
}
453437

454438
try {
455-
const result = await flushInstallQueue({
456-
queue: {
457-
get: () => queuedServerInstalls.value,
458-
set: (plans: Map<string, BrowseInstallPlan<InstallableSearchResult>>) => {
459-
queuedServerInstalls.value = plans
460-
writeStoredQueue(serverId, worldId, plans)
461-
},
462-
},
463-
install: async (plan) => {
464-
await client.archon.content_v1.addAddon(serverId, worldId, {
465-
project_id: plan.projectId,
466-
version_id: plan.versionId,
467-
})
468-
installedProjectIds.add(plan.projectId)
469-
},
470-
onError: (error, plan) => {
471-
removePendingServerContentInstall(serverId, worldId, plan.projectId)
472-
handleError(error as Error)
473-
},
474-
onProgress: (completed, total) => {
475-
queuedInstallProgress.value = { completed, total }
476-
},
439+
const result = await flushStoredServerAddonInstallQueue({
440+
serverId,
441+
worldId,
442+
install: (plans) =>
443+
client.archon.content_v1.addAddons(
444+
serverId,
445+
worldId,
446+
plans.map((plan) => ({
447+
project_id: plan.projectId,
448+
version_id: plan.versionId,
449+
})),
450+
),
451+
onQueueChange: (plans) => setStoredServerInstallPlans(serverId, worldId, plans),
477452
})
478453

479-
if (installedProjectIds.size > 0) {
480-
serverContentProjectIds.value = new Set([
481-
...serverContentProjectIds.value,
482-
...installedProjectIds,
483-
])
484-
serverContentInstallKeys.value = new Set([
485-
...serverContentInstallKeys.value,
486-
...installedProjectIds,
487-
])
454+
if (!result.ok) {
455+
for (const plan of result.attemptedPlans) {
456+
removePendingServerContentInstall(serverId, worldId, plan.projectId)
457+
}
458+
handleError(result.error as Error)
459+
return false
488460
}
489461

490-
return result.ok
462+
queuedInstallProgress.value = {
463+
completed: result.flushedPlans.length,
464+
total: result.flushedPlans.length,
465+
}
466+
serverContentProjectIds.value = new Set([
467+
...serverContentProjectIds.value,
468+
...result.flushedPlans.map((plan) => plan.projectId),
469+
])
470+
serverContentInstallKeys.value = new Set([
471+
...serverContentInstallKeys.value,
472+
...result.flushedPlans.map((plan) => plan.projectId),
473+
])
474+
475+
return true
491476
} finally {
492477
isInstallingQueuedServerInstalls.value = false
493478
queuedInstallProgress.value = { completed: 0, total: 0 }
@@ -522,17 +507,7 @@ export function createServerInstallContent(opts: {
522507
.catch((err) => handleError(err as Error))
523508
}
524509
await router.push(backUrl)
525-
526-
const ok = await flushQueuedServerInstalls(sid, wid)
527-
if (!ok) {
528-
queuedServerInstalls.value = new Map()
529-
writeStoredQueue(sid, wid, new Map())
530-
addNotification({
531-
type: 'error',
532-
title: 'Some projects failed to install',
533-
text: 'Failed projects were not added. You can try installing them again.',
534-
})
535-
}
510+
void flushQueuedServerInstalls(sid, wid)
536511

537512
return true
538513
}
@@ -545,7 +520,7 @@ export function createServerInstallContent(opts: {
545520
plans: Map<string, BrowseInstallPlan<InstallableSearchResult>>,
546521
) {
547522
queuedServerInstalls.value = plans
548-
writeStoredQueue(serverIdQuery.value, effectiveServerWorldId.value, plans)
523+
writeStoredServerInstallQueue(serverIdQuery.value, effectiveServerWorldId.value, plans)
549524
}
550525

551526
function onServerFlowBack() {

0 commit comments

Comments
 (0)