Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions electron/trpc/data/games.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ export const dataGamesRouter = t.router({
.input(z.object({ gameId: z.string().min(1).nullable() }))
.mutation(async ({ input }) => {
const db = getDb()
await db.transaction(async (tx) => {
await tx.update(game).set({ isDefault: false }).where(eq(game.isDefault, true))
db.transaction((tx) => {
tx.update(game).set({ isDefault: false }).where(eq(game.isDefault, true)).run()
if (input.gameId != null) {
await tx.update(game).set({ isDefault: true }).where(eq(game.id, input.gameId))
tx.update(game).set({ isDefault: true }).where(eq(game.id, input.gameId)).run()
}
})
}),
Expand Down
62 changes: 36 additions & 26 deletions electron/trpc/data/profiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,33 +55,35 @@ export const dataProfilesRouter = t.router({
const db = getDb()
const defaultId = `${input.gameId}-default`

return await db.transaction(async (tx) => {
return db.transaction((tx) => {
// Check if default profile exists
const existing = await tx
const existing = tx
.select()
.from(profile)
.where(eq(profile.id, defaultId))
.limit(1)
.all()

if (!existing[0]) {
await tx.insert(profile).values({
tx.insert(profile).values({
id: defaultId,
gameId: input.gameId,
name: "Default",
isDefault: true,
isActive: false,
})
}).run()
}

// If no active profile for this game, set default as active
const active = await tx
const active = tx
.select()
.from(profile)
.where(and(eq(profile.gameId, input.gameId), eq(profile.isActive, true)))
.limit(1)
.all()

if (!active[0]) {
await tx.update(profile).set({ isActive: true }).where(eq(profile.id, defaultId))
tx.update(profile).set({ isActive: true }).where(eq(profile.id, defaultId)).run()
}

return defaultId
Expand All @@ -98,23 +100,24 @@ export const dataProfilesRouter = t.router({
const db = getDb()
const newId = `${input.gameId}-${randomUUID()}`

return await db.transaction(async (tx) => {
return db.transaction((tx) => {
// Deactivate current active profile
await tx
tx
.update(profile)
.set({ isActive: false })
.where(and(eq(profile.gameId, input.gameId), eq(profile.isActive, true)))
.run()

// Insert new profile as active
const now = new Date().toISOString()
await tx.insert(profile).values({
tx.insert(profile).values({
id: newId,
gameId: input.gameId,
name: input.name,
isDefault: false,
isActive: true,
createdAt: now,
})
}).run()

return {
id: newId,
Expand Down Expand Up @@ -148,13 +151,14 @@ export const dataProfilesRouter = t.router({
.mutation(async ({ input }) => {
const db = getDb()

return await db.transaction(async (tx) => {
return db.transaction((tx) => {
// Check if it's the default profile
const target = await tx
const target = tx
.select()
.from(profile)
.where(and(eq(profile.id, input.profileId), eq(profile.gameId, input.gameId)))
.limit(1)
.all()

if (!target[0]) {
return { deleted: false as boolean, reason: "Profile not found" as string | undefined }
Expand All @@ -168,32 +172,34 @@ export const dataProfilesRouter = t.router({
if (target[0].isActive) {
const defaultId = `${input.gameId}-default`
// Try default profile first
const defaultProfile = await tx
const defaultProfile = tx
.select()
.from(profile)
.where(eq(profile.id, defaultId))
.limit(1)
.all()

if (defaultProfile[0]) {
await tx.update(profile).set({ isActive: true }).where(eq(profile.id, defaultId))
tx.update(profile).set({ isActive: true }).where(eq(profile.id, defaultId)).run()
} else {
// Fall back to any other profile
const other = await tx
const other = tx
.select()
.from(profile)
.where(and(
eq(profile.gameId, input.gameId),
eq(profile.isActive, false),
))
.limit(1)
.all()
if (other[0]) {
await tx.update(profile).set({ isActive: true }).where(eq(profile.id, other[0].id))
tx.update(profile).set({ isActive: true }).where(eq(profile.id, other[0].id)).run()
}
}
}

// Delete the profile (cascade deletes profileMod rows)
await tx.delete(profile).where(eq(profile.id, input.profileId))
tx.delete(profile).where(eq(profile.id, input.profileId)).run()
return { deleted: true as boolean, reason: undefined as string | undefined }
})
}),
Expand All @@ -206,17 +212,19 @@ export const dataProfilesRouter = t.router({
}))
.mutation(async ({ input }) => {
const db = getDb()
await db.transaction(async (tx) => {
db.transaction((tx) => {
// Deactivate all profiles for this game
await tx
tx
.update(profile)
.set({ isActive: false })
.where(and(eq(profile.gameId, input.gameId), eq(profile.isActive, true)))
.run()
// Activate target
await tx
tx
.update(profile)
.set({ isActive: true })
.where(eq(profile.id, input.profileId))
.run()
})
}),

Expand All @@ -227,29 +235,31 @@ export const dataProfilesRouter = t.router({
const db = getDb()
const defaultId = `${input.gameId}-default`

return await db.transaction(async (tx) => {
return db.transaction((tx) => {
// Delete all non-default profiles (cascade cleans profileMod)
await tx
tx
.delete(profile)
.where(and(eq(profile.gameId, input.gameId), eq(profile.isDefault, false)))
.run()

// Ensure default profile exists
const existing = await tx
const existing = tx
.select()
.from(profile)
.where(eq(profile.id, defaultId))
.limit(1)
.all()

if (!existing[0]) {
await tx.insert(profile).values({
tx.insert(profile).values({
id: defaultId,
gameId: input.gameId,
name: "Default",
isDefault: true,
isActive: true,
})
}).run()
} else {
await tx.update(profile).set({ isActive: true }).where(eq(profile.id, defaultId))
tx.update(profile).set({ isActive: true }).where(eq(profile.id, defaultId)).run()
}

return defaultId
Expand Down
28 changes: 14 additions & 14 deletions src/components/app-bootstrap.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { useEffect, useRef } from "react"
import { useAppStore } from "@/store/app-store"
import {
useGameManagementData,
useGameManagementActions,
useProfileActions,
useSettingsData,
useSettingsActions,
useGames,
useAddGame,
useEnsureDefaultProfile,
useAllSettings,
useUpdateGlobalSettings,
} from "@/data"
import { DownloadBridge } from "@/components/download-bridge"
import { trpc, hasElectronTRPC } from "@/lib/trpc"
import { i18n } from "@/lib/i18n"

export function AppBootstrap() {
const hasInitialized = useRef(false)
const { defaultGameId } = useGameManagementData()
const gameMut = useGameManagementActions()
const profileMut = useProfileActions()
const { defaultGameId } = useGames()
const addGame = useAddGame()
const ensureDefaultProfile = useEnsureDefaultProfile()
const selectGame = useAppStore((s) => s.selectGame)
const { global: globalSettings, getPerGame } = useSettingsData()
const { updateGlobal } = useSettingsActions()
const { global: globalSettings, getPerGame } = useAllSettings()
const updateGlobal = useUpdateGlobalSettings()

useEffect(() => {
void i18n.changeLanguage(globalSettings.language)
Expand Down Expand Up @@ -49,21 +49,21 @@ export function AppBootstrap() {

// Apply updates if any
if (Object.keys(updates).length > 0) {
updateGlobal(updates)
updateGlobal.mutate(updates)
}
}, [defaultPathsQuery.data, globalSettings.dataFolder, globalSettings.steamFolder, updateGlobal])
}, [defaultPathsQuery.data, globalSettings.dataFolder, globalSettings.steamFolder, updateGlobal.mutate])

useEffect(() => {
if (hasInitialized.current || !defaultGameId) return
hasInitialized.current = true

// Ensure game is managed
gameMut.addManagedGame(defaultGameId)
addGame.mutate(defaultGameId)

// Only ensure profile if game has install folder set
const installFolder = getPerGame(defaultGameId).gameInstallFolder
if (installFolder?.trim()) {
profileMut.ensureDefaultProfile(defaultGameId)
ensureDefaultProfile.mutate(defaultGameId)
}

// Select the game
Expand Down
Loading
Loading