feat: Sync library executable state during installed games scan#2328
feat: Sync library executable state during installed games scan#2328IsaiahBideshi wants to merge 9 commits into
Conversation
Add a step during installed game scan that resets stale install metadata and disables automatic cloud sync when a game executable no longer exists. Expose in preload. Add UI elements that show which executables were cleared.
Greptile SummaryThis PR extends the "Scan PC for Installed Games" flow with a second step that clears stale executable paths (and disables automatic cloud sync) for library games whose executable file no longer exists on disk, then surfaces the results in the existing scan modal.
Confidence Score: 3/5Safe to review further but needs the custom-game filter fixed before merging — the removal step will silently wipe executable paths for manually-added library entries. The new removal handler omits the src/main/events/library/remove-uninstalled-game-executables.ts needs the missing shop filter; src/renderer/src/components/header/scan-games-modal.tsx has no loading indication while the removal step runs after the scan completes. Important Files Changed
Sequence DiagramsequenceDiagram
participant UI as ScanGamesModal
participant Header as Header (renderer)
participant Preload as preload/ipcRenderer
participant Scan as scanInstalledGames (main)
participant Remove as removeUninstalledGameExecutables (main)
participant DB as gamesSublevel (LevelDB)
participant WM as WindowManager
UI->>Header: onStartScan()
Header->>Header: setIsScanning(true), setScanResult(null), setRemoveExeResult(null)
Header->>Preload: scanInstalledGames(dirs, includeDefault)
Preload->>Scan: IPC invoke
Scan->>DB: iterator().all() filter !isDeleted and shop not custom
Scan->>DB: put(key, updatedGame) for each found executable
Scan->>WM: sendToAppWindows on-library-batch-complete
Scan-->>Header: foundGames and total
Header->>Header: setScanResult(result)
Header->>Preload: removeUninstalledGameExecutables()
Preload->>Remove: IPC invoke
Remove->>DB: iterator().all() filter !isDeleted only missing shop guard
Remove->>DB: put(key, cleared game) for each missing executable
Remove->>WM: "sendToAppWindows on-library-batch-complete only if removed > 0"
Remove-->>Header: removedGames and total
Header->>Header: setRemoveExeResult(result) and setIsScanning(false)
Header->>UI: render scan and removal results
Reviews (1): Last reviewed commit: "feat: Sync library executable state duri..." | Re-trigger Greptile |
| .iterator() | ||
| .all() | ||
| .then((results) => | ||
| results | ||
| .filter(([_key, game]) => game.isDeleted === false) | ||
| .map(([key, game]) => ({ key, game })) |
There was a problem hiding this comment.
Custom-shop games incorrectly included in executable removal
The filter here does not exclude games with shop === "custom", but scanInstalledGames explicitly does (game.isDeleted === false && game.shop !== "custom"). This inconsistency means the removal step will clear executable paths for custom (manually-added) games that the scan never touched, silently breaking those library entries for users who have manually configured them.
| if (removedGames.length > 0) { | ||
| WindowManager.sendToAppWindows("on-library-batch-complete"); | ||
| } | ||
| return { removedGames: removedGames, total: gamesToCheck.length }; |
There was a problem hiding this comment.
There is no progress indicator during the executable-removal step. After
scanInstalledGames completes, isScanning is still true but scanResult is now set, so the spinner (isScanning && !scanResult) is hidden. The user sees scan results but has no indication that the second step (removal) is still running. Consider adding a separate isRemovingExecutables flag and a corresponding loading state in the modal.
| if (removedGames.length > 0) { | |
| WindowManager.sendToAppWindows("on-library-batch-complete"); | |
| } | |
| return { removedGames: removedGames, total: gamesToCheck.length }; | |
| WindowManager.sendToAppWindows("on-library-batch-complete"); | |
| return { removedGames: removedGames, total: gamesToCheck.length }; |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Add status to removing executables. Filter out custom add games.
chubbygrannychaser
left a comment
There was a problem hiding this comment.
Found one ordering issue in the library sync flow.
| setScanResult(result); | ||
| setIsScanning(false); | ||
| setIsRemovingExecutables(true); | ||
| const exeResult = |
There was a problem hiding this comment.
This cleanup runs after scanInstalledGames, but the scan only considers games where !game.executablePath. A game with a stale executable path is therefore skipped by this scan, then cleared here, so if it is actually installed elsewhere the same sync pass won't rediscover it; the user has to run sync a second time. Please clear missing executable paths before calling scanInstalledGames, or have the scan include entries whose current executable path no longer exists.
chubbygrannychaser
left a comment
There was a problem hiding this comment.
The previous ordering issue is fixed, but I found one remaining modal state issue.
| clickOutsideToClose={!isScanning && !isRemovingExecutables} | ||
| > | ||
| <div className="scan-games-modal"> | ||
| {!scanResult && !isScanning && ( |
There was a problem hiding this comment.
When isRemovingExecutables is true, isScanning is already false and scanResult is still null, so this initial options block remains visible at the same time as the new removal spinner below. Please also gate this on !isRemovingExecutables so users don't see the scan options/buttons while the cleanup step is running.
Hachi-R
left a comment
There was a problem hiding this comment.
there are still a few sonar issues left. could you please fix them before this can be merged?
| "scan_games_detection_warning": "Detection relies on a community-maintained list of known games and may be outdated, so some games might not be found." | ||
| "scan_games_detection_warning": "Detection relies on a community-maintained list of known games and may be outdated, so some games might not be found.", | ||
| "remove_executables_in_progress": "Checking for uninstalled game executables...", | ||
| "remove_executables_result": "Removed {{removed}} of {{total}} uninstalled game executables", |
There was a problem hiding this comment.
total seems to be the number of games checked, not the number of uninstalled executables, so removed {{removed}} of {{total}} uninstalled game executables can sound like all checked games were uninstalled.
could you please adjust this text to something like removed {{removed}} stale executable paths from {{total}} checked games or simply removed {{removed}} stale executable paths?
|




Add a step during installed game scan that resets stale install metadata and disables automatic cloud sync when a game executable no longer exists.
Expose in preload.
Add UI elements that show which executables were cleared.
When submitting this pull request, I confirm the following (please check the boxes):
Fill in the PR content:
There was some undesirable behaviour after deleting a game from your files and not in the launcher, the game is still marked as installed. This PR adds to the "Scan PC for Installed Games" feature, it removes any games in the library whose executable file no longer exists on the PC. I've also changed the wording on the button and in the modal to better match what the scan now does which is sync the library.