feat(mobx): migrate legacy data

This commit is contained in:
Paul 2021-12-24 11:19:02 +00:00
parent e89bbb7455
commit 74430b1a8f
2 changed files with 105 additions and 13 deletions

View file

@ -4,6 +4,8 @@ import localforage from "localforage";
import { makeAutoObservable, reaction } from "mobx"; import { makeAutoObservable, reaction } from "mobx";
import { Client } from "revolt.js"; import { Client } from "revolt.js";
import { legacyMigrateForwards, LegacyState } from "./legacy/redux";
import Persistent from "./interfaces/Persistent"; import Persistent from "./interfaces/Persistent";
import Syncable from "./interfaces/Syncable"; import Syncable from "./interfaces/Syncable";
import Auth from "./stores/Auth"; import Auth from "./stores/Auth";
@ -89,10 +91,23 @@ export default class State {
} }
} }
/**
* Temporarily ignore updates to a key.
* @param key Key to ignore
*/
setDisabled(key: string) { setDisabled(key: string) {
this.disabled.add(key); this.disabled.add(key);
} }
/**
* Save to disk.
*/
async save() {
for (const [id, store] of this.persistent) {
await localforage.setItem(id, store.toJSON());
}
}
/** /**
* Register reaction listeners for persistent data stores. * Register reaction listeners for persistent data stores.
* @returns Function to dispose of listeners * @returns Function to dispose of listeners
@ -177,6 +192,20 @@ export default class State {
* Load data stores from local storage. * Load data stores from local storage.
*/ */
async hydrate() { async hydrate() {
// Migrate legacy Redux store.
let legacy = await localforage.getItem("state");
if (legacy) {
if (typeof legacy === "string") {
legacy = JSON.parse(legacy);
}
legacyMigrateForwards(legacy as Partial<LegacyState>, this);
await localforage.removeItem("state");
await this.save();
return;
}
// Load MobX store.
const sync = (await localforage.getItem("sync")) as DataSync; const sync = (await localforage.getItem("sync")) as DataSync;
if (sync) { if (sync) {
const { revision } = sync; const { revision } = sync;
@ -205,15 +234,3 @@ export async function hydrateState() {
export function useApplicationState() { export function useApplicationState() {
return state; return state;
} }
/**
*
* Redux hydration:
* localForage.getItem("state").then((s) => {
if (s !== null) {
dispatch({ type: "__INIT", state: s as State });
}
state.hydrate().then(() => setLoaded(true));
});
*/

View file

@ -1,8 +1,15 @@
import { runInAction } from "mobx";
import { Session } from "revolt-api/types/Auth"; import { Session } from "revolt-api/types/Auth";
import { Language } from "../../context/Locale"; import { Language } from "../../context/Locale";
import { Fonts, MonospaceFonts, Overrides } from "../../context/Theme"; import {
Fonts,
MonospaceFonts,
Overrides,
ThemeOptions,
} from "../../context/Theme";
import State from "../State";
import { Data as DataAuth } from "../stores/Auth"; import { Data as DataAuth } from "../stores/Auth";
import { Data as DataLocaleOptions } from "../stores/LocaleOptions"; import { Data as DataLocaleOptions } from "../stores/LocaleOptions";
import { Data as DataNotificationOptions } from "../stores/NotificationOptions"; import { Data as DataNotificationOptions } from "../stores/NotificationOptions";
@ -62,6 +69,11 @@ export interface LegacyAuthState {
active?: string; active?: string;
} }
export interface LegacySettings {
theme?: LegacyThemeOptions;
appearance?: LegacyAppearanceOptions;
}
export function legacyMigrateAuth(auth: LegacyAuthState): DataAuth { export function legacyMigrateAuth(auth: LegacyAuthState): DataAuth {
return { return {
current: auth.active, current: auth.active,
@ -100,6 +112,20 @@ export function legacyMigrateAppearance(
}; };
} }
/**
* Remove trolling from an object
* @param inp Object to remove trolling from
* @returns Object without trolling
*/
function detroll(inp: object): ISettings {
const obj: object = {};
Object.keys(inp)
.filter((x) => typeof (inp as any)[x] !== "undefined")
.map((x) => ((obj as any)[x] = (inp as any)[x]));
return obj as unknown as ISettings;
}
export function legacyMigrateNotification( export function legacyMigrateNotification(
channel: LegacyNotifications, channel: LegacyNotifications,
): DataNotificationOptions { ): DataNotificationOptions {
@ -116,3 +142,52 @@ export function legacyMigrateSync(sync: LegacySyncOptions): DataSync {
}, },
}; };
} }
export type LegacyState = {
locale: Language;
auth: LegacyAuthState;
settings: LegacySettings;
sync: LegacySyncOptions;
notifications: LegacyNotifications;
};
export function legacyMigrateForwards(
data: Partial<LegacyState>,
target: State,
) {
runInAction(() => {
if ("sync" in data) {
target.sync.hydrate(legacyMigrateSync(data.sync!));
}
if ("locale" in data) {
target.locale.hydrate(legacyMigrateLocale(data.locale!));
}
if ("auth" in data) {
target.auth.hydrate(legacyMigrateAuth(data.auth!));
}
if ("settings" in data) {
if (data!.settings!.theme) {
target.settings.hydrate(
detroll(legacyMigrateTheme(data.settings!.theme!)),
);
}
if (data!.settings!.appearance) {
target.settings.hydrate(
detroll(
legacyMigrateAppearance(data.settings!.appearance!),
),
);
}
}
if ("notifications" in data) {
target.notifications.hydrate(
legacyMigrateNotification(data.notifications!),
);
}
});
}