Skip to content

Commit

Permalink
Offer an option to reset local settings if loading them fails at launch
Browse files Browse the repository at this point in the history
If SettingsLoader fails to load the settings, a button for clearing out
the IndexedDB containing local settings is shown. Also offers different
suggestions for solutions based on what went wrong.

Refs TS-1384
  • Loading branch information
anttimaki committed Dec 15, 2022
1 parent 611e68b commit 5bef517
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 23 deletions.
118 changes: 95 additions & 23 deletions src/components/SettingsLoader.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,50 @@
<template>
<div id="settings-loader">
<slot v-if="isLoaded" />
<slot v-if="phase === PHASES.LOADED" />

<div v-else :class="['modal', 'z-top', {'is-active': error}]">
<div v-if="phase > PHASES.LOADED" class="modal z-top is-active">
<div class="modal-content">
<div class="notification is-danger">
<h3 class="title">Error</h3>
<h5 class="title is-5">{{error && error.name}}</h5>
<p>{{error && error.message}}</p>
<div v-if="error && error.solution">
<br/>
<h5 class="title is-5">Suggestion</h5>
<p>{{error && error.solution}}</p>
<br />
<h5 class="title is-5">Suggestion</h5>

<p v-if="phase === PHASES.GAME_FAILED">
This is a problem with the mod manager itself.
If there's a newer version of the manager
available, try installing it.
</p>

<div v-else-if="phase === PHASES.SETTINGS_FAILED">
<p>
Loading of local user settings failed. You
can use the button below to reset the
settings, but note that all settings for all
games will be lost and this can't be undone.
This won't affect the loaded mods or mod profiles.
</p>
<br />
<button @click="resetSettings">Reset settings</button>
</div>

<p v-else-if="phase === PHASES.RESET_FAILED">
Well, that's awkward. Resetting of the settings
failed as well. You can still try to reset the
settings manually by following these
<a target="_blank" rel="noopener noreferrer"
href="https://github.com/ebkr/r2modmanPlus/wiki/Error:-White-or-blank-game-select-screen-on-startup#corrupted-settings-on-update">
instructions.
</a>
</p>

<p v-else-if="phase === PHASES.RETRY_FAILED">
That didn't do much, it seems. Locally stored
settings were reset, but that didn't solve the
problem. If there's a newer version of the
manager available, try installing it.
</p>
</div>
</div>
</div>
Expand All @@ -27,16 +59,23 @@ import R2Error from "../model/errors/R2Error";
import GameManager from "../model/game/GameManager";
import ManagerSettings from "../r2mm/manager/ManagerSettings";
const url = "https://github.com/ebkr/r2modmanPlus/wiki/Error:-White-or-blank-game-select-screen-on-startup";
const solution = `Resetting settings might help. For more information, see ${url}`;
enum PHASES {
INITIAL,
LOADED,
GAME_FAILED,
SETTINGS_FAILED,
RESET_FAILED,
RETRY_FAILED
}
@Component
export default class SettingsLoader extends Vue {
@Prop({required: true})
private logError!: (error: R2Error) => void;
error: R2Error|null = null;
isLoaded = false;
PHASES = PHASES;
phase = PHASES.INITIAL;
get defaultGame() {
const defaultGame = GameManager.unsetGame();
Expand All @@ -49,43 +88,76 @@ export default class SettingsLoader extends Vue {
return defaultGame;
}
handleError(name: string, message: string, solution: string|null = null) {
this.error = new R2Error(name, message, solution);
handleError(name: string, message: string) {
this.error = new R2Error(name, message);
this.logError(this.error);
}
async created() {
let defaultGame;
async loadSettings() {
const isRetry = this.phase === PHASES.SETTINGS_FAILED;
let settings;
let error;
try {
defaultGame = this.defaultGame;
// We know by now that this.defaultGame is safe to use.
settings = await ManagerSettings.getSingleton(this.defaultGame);
} catch (e) {
this.handleError("Failed to read default game", `${e}`);
this.handleError("Failed to read ManagerSettings", `${e}`);
this.phase = isRetry ? PHASES.RETRY_FAILED : PHASES.SETTINGS_FAILED;
return;
}
try {
settings = await ManagerSettings.getSingleton(defaultGame);
// Force reload settings from Dexie just to be sure although
// .getSingleton() should have done it already.
error = await settings.load(true);
} catch (e) {
this.handleError("Failed to read ManagerSettings", `${e}`, solution);
this.handleError("Failed to load ManagerSettings", `${e}`);
this.phase = isRetry ? PHASES.RETRY_FAILED : PHASES.SETTINGS_FAILED;
return;
}
if (error) {
this.handleError(error.name, error.message);
this.phase = isRetry ? PHASES.RETRY_FAILED : PHASES.SETTINGS_FAILED;
return;
}
this.phase = PHASES.LOADED;
}
async resetSettings() {
try {
error = await settings.load();
await ManagerSettings.resetLocalSettings();
} catch (e) {
this.handleError("Failed to load ManagerSettings", `${e}`, solution);
this.handleError("Failed to reset IndexedDB", `${e}`);
this.phase = PHASES.RESET_FAILED;
return;
}
if (error) {
this.handleError(error.name, error.message, solution);
try {
await this.loadSettings();
} catch (e) {
this.handleError("Unexpected ManagerSettings error", `${e}`);
this.phase = PHASES.RETRY_FAILED;
}
}
async created() {
try {
this.defaultGame;
} catch (e) {
this.handleError("Failed to read game definitions", `${e}`);
this.phase = PHASES.GAME_FAILED;
return;
}
this.isLoaded = true;
try {
await this.loadSettings();
} catch (e) {
this.handleError("Unexpected ManagerSettings error", `${e}`);
this.phase = PHASES.SETTINGS_FAILED;
}
}
}
</script>
12 changes: 12 additions & 0 deletions src/r2mm/manager/ManagerSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ export default class ManagerSettings {
await settings.save();
}

/**
* Clear local settings stored in IndexedDB.
*/
public static async resetLocalSettings() {
await ManagerSettings.DEXIE_STORE.delete();

// If Dexie store initiation failed when getSingleton() was
// called, we have partial settings that should be reset so the
// next getSingleton() call re-initiates things.
this.LOADED_SETTINGS = undefined;
}

public async load(forceRefresh?: boolean): Promise<R2Error | void> {
try {
if (ManagerSettings.CONTEXT === undefined || forceRefresh === true) {
Expand Down

0 comments on commit 5bef517

Please sign in to comment.