fix(Map): Add common migration mechanism. ATTENTION! This is a non-reversible stored map settings commit — it means we do not guarantee that settings will work if you check out back. We’ve tried to migrate old settings, but it may not work well or may NOT work at all.

This commit is contained in:
DanSylvest
2025-09-24 11:03:17 +03:00
parent 34d3d92afd
commit 51ff4e7f36
26 changed files with 145 additions and 206 deletions

View File

@@ -1,4 +1,4 @@
import { MapUserSettings, SettingsWithVersion } from '@/hooks/Mapper/mapRootProvider/types.ts'; import { MapUserSettings, SettingsWrapper } from '@/hooks/Mapper/mapRootProvider/types.ts';
export const REQUIRED_KEYS = [ export const REQUIRED_KEYS = [
'widgets', 'widgets',
@@ -19,11 +19,8 @@ export class MapUserSettingsParseError extends Error {
} }
} }
const isNumber = (v: unknown): v is number => typeof v === 'number' && !Number.isNaN(v); /** Minimal check that an object matches SettingsWrapper<*> */
const isSettings = (v: unknown): v is SettingsWrapper<unknown> => typeof v === 'object' && v !== null;
/** Minimal check that an object matches SettingsWithVersion<*> */
const isSettingsWithVersion = (v: unknown): v is SettingsWithVersion<unknown> =>
typeof v === 'object' && v !== null && isNumber((v as any).version) && 'settings' in (v as any);
/** Ensure every required key is present */ /** Ensure every required key is present */
const hasAllRequiredKeys = (v: unknown): v is Record<RequiredKeys, unknown> => const hasAllRequiredKeys = (v: unknown): v is Record<RequiredKeys, unknown> =>
@@ -52,8 +49,8 @@ export const parseMapUserSettings = (json: unknown): MapUserSettings => {
} }
for (const key of REQUIRED_KEYS) { for (const key of REQUIRED_KEYS) {
if (!isSettingsWithVersion((data as any)[key])) { if (!isSettings((data as any)[key])) {
throw new MapUserSettingsParseError(`"${key}" must match SettingsWithVersion<T>`); throw new MapUserSettingsParseError(`"${key}" must match SettingsWrapper<T>`);
} }
} }

View File

@@ -5,6 +5,7 @@ import { parseMapUserSettings } from '@/hooks/Mapper/components/helpers';
import { saveTextFile } from '@/hooks/Mapper/utils/saveToFile.ts'; import { saveTextFile } from '@/hooks/Mapper/utils/saveToFile.ts';
import { SplitButton } from 'primereact/splitbutton'; import { SplitButton } from 'primereact/splitbutton';
import { loadTextFile } from '@/hooks/Mapper/utils'; import { loadTextFile } from '@/hooks/Mapper/utils';
import { applyMigrations } from '@/hooks/Mapper/mapRootProvider/migrations';
export const ImportExport = () => { export const ImportExport = () => {
const { const {
@@ -22,8 +23,9 @@ export const ImportExport = () => {
} }
try { try {
// INFO: WE NOT SUPPORT MIGRATIONS FOR OLD FILES AND Clipboard
const parsed = parseMapUserSettings(text); const parsed = parseMapUserSettings(text);
if (applySettings(parsed)) { if (applySettings(applyMigrations(parsed))) {
toast.current?.show({ toast.current?.show({
severity: 'success', severity: 'success',
summary: 'Import', summary: 'Import',
@@ -59,8 +61,9 @@ export const ImportExport = () => {
try { try {
const text = await loadTextFile(); const text = await loadTextFile();
// INFO: WE NOT SUPPORT MIGRATIONS FOR OLD FILES AND Clipboard
const parsed = parseMapUserSettings(text); const parsed = parseMapUserSettings(text);
if (applySettings(parsed)) { if (applySettings(applyMigrations(parsed))) {
toast.current?.show({ toast.current?.show({
severity: 'success', severity: 'success',
summary: 'Import', summary: 'Import',

View File

@@ -1,7 +1,6 @@
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider'; import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import { useCallback, useEffect, useRef, useState } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
import { Toast } from 'primereact/toast'; import { Toast } from 'primereact/toast';
import { parseMapUserSettings } from '@/hooks/Mapper/components/helpers';
import { Button } from 'primereact/button'; import { Button } from 'primereact/button';
import { OutCommand } from '@/hooks/Mapper/types'; import { OutCommand } from '@/hooks/Mapper/types';
import { createDefaultWidgetSettings } from '@/hooks/Mapper/mapRootProvider/helpers/createDefaultWidgetSettings.ts'; import { createDefaultWidgetSettings } from '@/hooks/Mapper/mapRootProvider/helpers/createDefaultWidgetSettings.ts';
@@ -9,6 +8,7 @@ import { callToastSuccess } from '@/hooks/Mapper/helpers';
import { ConfirmPopup } from 'primereact/confirmpopup'; import { ConfirmPopup } from 'primereact/confirmpopup';
import { useConfirmPopup } from '@/hooks/Mapper/hooks'; import { useConfirmPopup } from '@/hooks/Mapper/hooks';
import { RemoteAdminSettingsResponse } from '@/hooks/Mapper/mapRootProvider/types.ts'; import { RemoteAdminSettingsResponse } from '@/hooks/Mapper/mapRootProvider/types.ts';
import { applyMigrations } from '@/hooks/Mapper/mapRootProvider/migrations';
export const ServerSettings = () => { export const ServerSettings = () => {
const { const {
@@ -34,7 +34,8 @@ export const ServerSettings = () => {
} }
try { try {
applySettings(parseMapUserSettings(res.default_settings)); //INFO: INSTEAD CHECK WE WILL TRY TO APPLY MIGRATION
applySettings(applyMigrations(JSON.parse(res.default_settings)));
callToastSuccess(toast.current, 'Settings synchronized successfully'); callToastSuccess(toast.current, 'Settings synchronized successfully');
} catch (error) { } catch (error) {
applySettings(createDefaultWidgetSettings()); applySettings(createDefaultWidgetSettings());

View File

@@ -1,4 +1,4 @@
import { MapUserSettings, MigrationTypes, SettingsWithVersion } from '@/hooks/Mapper/mapRootProvider/types.ts'; import { MapUserSettings, SettingsTypes, SettingsWrapper } from '@/hooks/Mapper/mapRootProvider/types.ts';
import { import {
DEFAULT_KILLS_WIDGET_SETTINGS, DEFAULT_KILLS_WIDGET_SETTINGS,
DEFAULT_ON_THE_MAP_SETTINGS, DEFAULT_ON_THE_MAP_SETTINGS,
@@ -8,45 +8,44 @@ import {
STORED_INTERFACE_DEFAULT_VALUES, STORED_INTERFACE_DEFAULT_VALUES,
} from '@/hooks/Mapper/mapRootProvider/constants.ts'; } from '@/hooks/Mapper/mapRootProvider/constants.ts';
import { DEFAULT_SIGNATURE_SETTINGS } from '@/hooks/Mapper/constants/signatures.ts'; import { DEFAULT_SIGNATURE_SETTINGS } from '@/hooks/Mapper/constants/signatures.ts';
import { SETTING_VERSIONS } from '@/hooks/Mapper/mapRootProvider/versions.ts'; import { STORED_SETTINGS_VERSION } from '@/hooks/Mapper/mapRootProvider/version.ts';
// TODO - we need provide and compare version // TODO - we need provide and compare version
export const createWidgetSettingsWithVersion = <T>(version: number, settings: T) => { export const createWidgetSettings = <T>(settings: T) => {
return { return settings;
version,
settings,
};
}; };
export const createDefaultWidgetSettings = (): MapUserSettings => { export const createDefaultWidgetSettings = (): MapUserSettings => {
return { return {
killsWidget: createWidgetSettingsWithVersion(SETTING_VERSIONS.kills, DEFAULT_KILLS_WIDGET_SETTINGS), version: STORED_SETTINGS_VERSION,
localWidget: createWidgetSettingsWithVersion(SETTING_VERSIONS.localWidget, DEFAULT_WIDGET_LOCAL_SETTINGS), migratedFromOld: true,
widgets: createWidgetSettingsWithVersion(SETTING_VERSIONS.widgets, getDefaultWidgetProps()), killsWidget: createWidgetSettings(DEFAULT_KILLS_WIDGET_SETTINGS),
routes: createWidgetSettingsWithVersion(SETTING_VERSIONS.routes, DEFAULT_ROUTES_SETTINGS), localWidget: createWidgetSettings(DEFAULT_WIDGET_LOCAL_SETTINGS),
onTheMap: createWidgetSettingsWithVersion(SETTING_VERSIONS.onTheMap, DEFAULT_ON_THE_MAP_SETTINGS), widgets: createWidgetSettings(getDefaultWidgetProps()),
signaturesWidget: createWidgetSettingsWithVersion(SETTING_VERSIONS.signatures, DEFAULT_SIGNATURE_SETTINGS), routes: createWidgetSettings(DEFAULT_ROUTES_SETTINGS),
interface: createWidgetSettingsWithVersion(SETTING_VERSIONS.interface, STORED_INTERFACE_DEFAULT_VALUES), onTheMap: createWidgetSettings(DEFAULT_ON_THE_MAP_SETTINGS),
signaturesWidget: createWidgetSettings(DEFAULT_SIGNATURE_SETTINGS),
interface: createWidgetSettings(STORED_INTERFACE_DEFAULT_VALUES),
}; };
}; };
// INFO - in another case need to generate complex type - but looks like it unnecessary // INFO - in another case need to generate complex type - but looks like it unnecessary
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export const getDefaultSettingsByType = (type: MigrationTypes): SettingsWithVersion<any> => { export const getDefaultSettingsByType = (type: SettingsTypes): SettingsWrapper<any> => {
switch (type) { switch (type) {
case MigrationTypes.killsWidget: case SettingsTypes.killsWidget:
return createWidgetSettingsWithVersion(SETTING_VERSIONS.kills, DEFAULT_KILLS_WIDGET_SETTINGS); return createWidgetSettings(DEFAULT_KILLS_WIDGET_SETTINGS);
case MigrationTypes.localWidget: case SettingsTypes.localWidget:
return createWidgetSettingsWithVersion(SETTING_VERSIONS.localWidget, DEFAULT_WIDGET_LOCAL_SETTINGS); return createWidgetSettings(DEFAULT_WIDGET_LOCAL_SETTINGS);
case MigrationTypes.widgets: case SettingsTypes.widgets:
return createWidgetSettingsWithVersion(SETTING_VERSIONS.widgets, getDefaultWidgetProps()); return createWidgetSettings(getDefaultWidgetProps());
case MigrationTypes.routes: case SettingsTypes.routes:
return createWidgetSettingsWithVersion(SETTING_VERSIONS.routes, DEFAULT_ROUTES_SETTINGS); return createWidgetSettings(DEFAULT_ROUTES_SETTINGS);
case MigrationTypes.onTheMap: case SettingsTypes.onTheMap:
return createWidgetSettingsWithVersion(SETTING_VERSIONS.onTheMap, DEFAULT_ON_THE_MAP_SETTINGS); return createWidgetSettings(DEFAULT_ON_THE_MAP_SETTINGS);
case MigrationTypes.signaturesWidget: case SettingsTypes.signaturesWidget:
return createWidgetSettingsWithVersion(SETTING_VERSIONS.signatures, DEFAULT_SIGNATURE_SETTINGS); return createWidgetSettings(DEFAULT_SIGNATURE_SETTINGS);
case MigrationTypes.interface: case SettingsTypes.interface:
return createWidgetSettingsWithVersion(SETTING_VERSIONS.interface, STORED_INTERFACE_DEFAULT_VALUES); return createWidgetSettings(STORED_INTERFACE_DEFAULT_VALUES);
} }
}; };

View File

@@ -6,7 +6,7 @@ import {
RemoteAdminSettingsResponse, RemoteAdminSettingsResponse,
} from '@/hooks/Mapper/mapRootProvider/types.ts'; } from '@/hooks/Mapper/mapRootProvider/types.ts';
import { createDefaultWidgetSettings } from '@/hooks/Mapper/mapRootProvider/helpers/createDefaultWidgetSettings.ts'; import { createDefaultWidgetSettings } from '@/hooks/Mapper/mapRootProvider/helpers/createDefaultWidgetSettings.ts';
import { parseMapUserSettings } from '@/hooks/Mapper/components/helpers'; import { applyMigrations } from '@/hooks/Mapper/mapRootProvider/migrations';
interface UseActualizeRemoteMapSettingsProps { interface UseActualizeRemoteMapSettingsProps {
outCommand: OutCommandHandler; outCommand: OutCommandHandler;
@@ -42,7 +42,7 @@ export const useActualizeRemoteMapSettings = ({
} }
try { try {
applySettings(parseMapUserSettings(res.default_settings)); applySettings(applyMigrations(JSON.parse(res.default_settings)));
} catch (error) { } catch (error) {
applySettings(createDefaultWidgetSettings()); applySettings(createDefaultWidgetSettings());
} }

View File

@@ -7,7 +7,8 @@ import fastDeepEqual from 'fast-deep-equal';
import { OutCommandHandler } from '@/hooks/Mapper/types'; import { OutCommandHandler } from '@/hooks/Mapper/types';
import { useActualizeRemoteMapSettings } from '@/hooks/Mapper/mapRootProvider/hooks/useActualizeRemoteMapSettings.ts'; import { useActualizeRemoteMapSettings } from '@/hooks/Mapper/mapRootProvider/hooks/useActualizeRemoteMapSettings.ts';
import { createDefaultWidgetSettings } from '@/hooks/Mapper/mapRootProvider/helpers/createDefaultWidgetSettings.ts'; import { createDefaultWidgetSettings } from '@/hooks/Mapper/mapRootProvider/helpers/createDefaultWidgetSettings.ts';
import { applyMigrations, migrations } from '@/hooks/Mapper/mapRootProvider/migrations'; import { applyMigrations, extractData } from '@/hooks/Mapper/mapRootProvider/migrations';
import { LS_KEY, LS_KEY_LEGASY } from '@/hooks/Mapper/mapRootProvider/version.ts';
const EMPTY_OBJ = {}; const EMPTY_OBJ = {};
@@ -15,7 +16,7 @@ export const useMapUserSettings = ({ map_slug }: MapRootData, outCommand: OutCom
const [isReady, setIsReady] = useState(false); const [isReady, setIsReady] = useState(false);
const [hasOldSettings, setHasOldSettings] = useState(false); const [hasOldSettings, setHasOldSettings] = useState(false);
const [mapUserSettings, setMapUserSettings] = useLocalStorageState<MapUserSettingsStructure>('map-user-settings', { const [mapUserSettings, setMapUserSettings] = useLocalStorageState<MapUserSettingsStructure>(LS_KEY, {
defaultValue: EMPTY_OBJ, defaultValue: EMPTY_OBJ,
}); });
@@ -101,18 +102,27 @@ export const useMapUserSettings = ({ map_slug }: MapRootData, outCommand: OutCom
return; return;
} }
if (mapUserSettings[map_slug] == null) { const currentMapUserSettings = mapUserSettings[map_slug];
if (currentMapUserSettings == null) {
return; return;
} }
const migratedResult = applyMigrations(map_slug, migrations); try {
if (!migratedResult) { // INFO: after migrations migratedFromOld always will be true
return; const migratedResult = applyMigrations(
!currentMapUserSettings.migratedFromOld ? extractData(LS_KEY_LEGASY) : currentMapUserSettings,
);
if (!migratedResult) {
setIsReady(true);
return;
}
setMapUserSettings({ ...mapUserSettings, [map_slug]: migratedResult });
setIsReady(true);
} catch (error) {
setIsReady(true);
} }
setMapUserSettings(migratedResult);
setIsReady(true);
}, [isReady, mapUserSettings, map_slug, setMapUserSettings]); }, [isReady, mapUserSettings, map_slug, setMapUserSettings]);
const checkOldSettings = useCallback(() => { const checkOldSettings = useCallback(() => {

View File

@@ -1,12 +1,7 @@
import { Dispatch, SetStateAction, useCallback, useMemo, useRef } from 'react'; import { Dispatch, SetStateAction, useCallback, useMemo, useRef } from 'react';
import { import { MapUserSettings, MapUserSettingsStructure, SettingsWrapper } from '@/hooks/Mapper/mapRootProvider/types.ts';
MapUserSettings,
MapUserSettingsStructure,
SettingsWithVersion,
} from '@/hooks/Mapper/mapRootProvider/types.ts';
type ExtractSettings<S extends keyof MapUserSettings> = type ExtractSettings<S extends keyof MapUserSettings> = MapUserSettings[S] extends SettingsWrapper<infer U> ? U : never;
MapUserSettings[S] extends SettingsWithVersion<infer U> ? U : never;
type Setter<S extends keyof MapUserSettings> = ( type Setter<S extends keyof MapUserSettings> = (
value: Partial<ExtractSettings<S>> | ((prev: ExtractSettings<S>) => Partial<ExtractSettings<S>>), value: Partial<ExtractSettings<S>> | ((prev: ExtractSettings<S>) => Partial<ExtractSettings<S>>),
@@ -25,21 +20,20 @@ export const useSettingsValueAndSetter = <S extends keyof MapUserSettings>(
if (!mapId) return {} as ExtractSettings<S>; if (!mapId) return {} as ExtractSettings<S>;
const mapSettings = settings[mapId]; const mapSettings = settings[mapId];
return (mapSettings?.[setting]?.settings ?? ({} as ExtractSettings<S>)) as ExtractSettings<S>; return (mapSettings?.[setting] ?? ({} as ExtractSettings<S>)) as ExtractSettings<S>;
}, [mapId, setting, settings]); }, [mapId, setting, settings]);
const refData = useRef({ mapId, setting, setSettings }); const refData = useRef({ mapId, setting, setSettings });
refData.current = { mapId, setting, setSettings }; refData.current = { mapId, setting, setSettings };
const setter = useCallback<Setter<S>>((value, v) => { const setter = useCallback<Setter<S>>(value => {
const { mapId, setting, setSettings } = refData.current; const { mapId, setting, setSettings } = refData.current;
if (!mapId) return; if (!mapId) return;
setSettings(all => { setSettings(all => {
const currentMap = all[mapId]; const currentMap = all[mapId];
const prev = currentMap[setting].settings as ExtractSettings<S>; const prev = currentMap[setting] as ExtractSettings<S>;
const version = v != null ? v : currentMap[setting].version;
const patch = const patch =
typeof value === 'function' ? (value as (p: ExtractSettings<S>) => Partial<ExtractSettings<S>>)(prev) : value; typeof value === 'function' ? (value as (p: ExtractSettings<S>) => Partial<ExtractSettings<S>>)(prev) : value;
@@ -48,10 +42,7 @@ export const useSettingsValueAndSetter = <S extends keyof MapUserSettings>(
...all, ...all,
[mapId]: { [mapId]: {
...currentMap, ...currentMap,
[setting]: { [setting]: { ...(prev as any), ...patch } as ExtractSettings<S>,
version,
settings: { ...(prev as any), ...patch } as ExtractSettings<S>,
},
}, },
}; };
}); });

View File

@@ -1,6 +0,0 @@
import { to_1 } from './to_1.ts';
import { to_2 } from './to_2.ts';
import { to_3 } from './to_3.ts';
import { MigrationStructure } from '@/hooks/Mapper/mapRootProvider/types.ts';
export default [to_1, to_2, to_3] as MigrationStructure[];

View File

@@ -1,13 +0,0 @@
import { MigrationStructure, MigrationTypes } from '@/hooks/Mapper/mapRootProvider/types.ts';
export const to_1: MigrationStructure = {
to: 1,
type: MigrationTypes.interface,
run: (prev: any) => {
return {
...prev,
test1: 'lol ke',
kek1: 'kek',
};
},
};

View File

@@ -1,14 +0,0 @@
import { MigrationStructure, MigrationTypes } from '@/hooks/Mapper/mapRootProvider/types.ts';
import { omit } from '@/hooks/Mapper/utils/omit.ts';
export const to_2: MigrationStructure = {
to: 2,
type: MigrationTypes.interface,
run: (prev: any) => {
return {
...omit(prev, ['test1', 'kek1']),
test2: 'lol ke1',
kek2: 'kek1',
};
},
};

View File

@@ -1,14 +0,0 @@
import { MigrationStructure, MigrationTypes } from '@/hooks/Mapper/mapRootProvider/types.ts';
import { omit } from '@/hooks/Mapper/utils/omit.ts';
export const to_3: MigrationStructure = {
to: 3,
type: MigrationTypes.interface,
run: (prev: any) => {
return {
...omit(prev, ['test2', 'kek2']),
test3: 'lol ke1333',
kek3: 'kek1333',
};
},
};

View File

@@ -1,7 +1,8 @@
import { MapUserSettingsStructure, MigrationStructure } from '@/hooks/Mapper/mapRootProvider/types.ts'; import { MapUserSettingsStructure } from '@/hooks/Mapper/mapRootProvider/types.ts';
import { getDefaultSettingsByType } from '@/hooks/Mapper/mapRootProvider/helpers/createDefaultWidgetSettings.ts'; import { STORED_SETTINGS_VERSION } from '@/hooks/Mapper/mapRootProvider/version.ts';
import { migrations } from '@/hooks/Mapper/mapRootProvider/migrations/index.ts';
const extractData = (localStoreKey = 'map-user-settings'): MapUserSettingsStructure | null => { export const extractData = (localStoreKey = 'map-user-settings'): MapUserSettingsStructure | null => {
const val = localStorage.getItem(localStoreKey); const val = localStorage.getItem(localStoreKey);
if (!val) { if (!val) {
return null; return null;
@@ -10,38 +11,46 @@ const extractData = (localStoreKey = 'map-user-settings'): MapUserSettingsStruct
return JSON.parse(val); return JSON.parse(val);
}; };
export const applyMigrations = ( export const applyMigrations = (mapSettings: any) => {
mapId: string, let currentMapSettings = { ...mapSettings };
migrations: MigrationStructure[],
localStoreKey = 'map-user-settings',
) => {
const currentLSData = extractData(localStoreKey);
// INFO if we have NO any data in store expected that we will use default // INFO if we have NO any data in store expected that we will use default
if (!currentLSData) { if (!currentMapSettings) {
return; return;
} }
const currentMapSettings = currentLSData[mapId]; const direction = STORED_SETTINGS_VERSION - (currentMapSettings.version || 0);
if (direction === 0) {
for (const migration of migrations) { if (currentMapSettings.version == null) {
const { to, run, type } = migration; return { ...currentMapSettings, version: STORED_SETTINGS_VERSION, migratedFromOld: true };
const currentValue = currentMapSettings[type];
if (!currentValue) {
currentMapSettings[type] = getDefaultSettingsByType(type);
continue;
} }
// we skip if current version is older return;
if (currentValue.version > to) {
continue;
}
const next = run(currentValue.settings);
currentMapSettings[type].version = to;
currentMapSettings[type].settings = next;
} }
return currentLSData; // Upgrade
if (direction > 0) {
const preparedMigrations = migrations.sort((a, b) => a.to - b.to).filter(x => x.to <= STORED_SETTINGS_VERSION);
for (const migration of preparedMigrations) {
const { to, up } = migration;
const next = up(currentMapSettings);
currentMapSettings = { ...next, version: to, migratedFromOld: true };
}
return currentMapSettings;
}
// DOWNGRADE
const preparedMigrations = migrations.sort((a, b) => b.to - a.to).filter(x => x.to - 1 >= STORED_SETTINGS_VERSION);
for (const migration of preparedMigrations) {
const { to, down } = migration;
const next = down(currentMapSettings);
currentMapSettings = { ...next, version: to - 1, migratedFromOld: true };
}
return currentMapSettings;
}; };

View File

@@ -1,18 +1,4 @@
import m_interface from './interface'; import list from './list';
import killsWidget from './killsWidget';
import localWidget from './localWidget';
import onTheMap from './onTheMap';
import routes from './routes';
import signaturesWidget from './signaturesWidget';
import widgets from './widgets';
export * from './applyMigrations.ts'; export * from './applyMigrations.ts';
export const migrations = [ export const migrations = [...list];
...m_interface,
...killsWidget,
...localWidget,
...onTheMap,
...routes,
...signaturesWidget,
...widgets,
];

View File

@@ -1,3 +0,0 @@
import { MigrationStructure } from '@/hooks/Mapper/mapRootProvider/types.ts';
export default [] as MigrationStructure[];

View File

@@ -1,3 +0,0 @@
import { MigrationStructure } from '@/hooks/Mapper/mapRootProvider/types.ts';
export default [] as MigrationStructure[];

View File

@@ -0,0 +1,4 @@
import { to_1 } from './to_1.ts';
import { MigrationStructure } from '@/hooks/Mapper/mapRootProvider/types.ts';
export default [to_1 /*to_2, to_3*/] as MigrationStructure[];

View File

@@ -0,0 +1,15 @@
import { MigrationStructure } from '@/hooks/Mapper/mapRootProvider/types.ts';
export const to_1: MigrationStructure = {
to: 1,
up: (prev: any) => {
return Object.keys(prev).reduce((acc, k) => {
return { ...acc, [k]: prev[k].settings };
}, Object.create(null));
},
down: (prev: any) => {
return Object.keys(prev).reduce((acc, k) => {
return { ...acc, [k]: { version: 0, settings: prev[k] } };
}, Object.create(null));
},
};

View File

@@ -1,3 +0,0 @@
import { MigrationStructure } from '@/hooks/Mapper/mapRootProvider/types.ts';
export default [] as MigrationStructure[];

View File

@@ -1,3 +0,0 @@
import { MigrationStructure } from '@/hooks/Mapper/mapRootProvider/types.ts';
export default [] as MigrationStructure[];

View File

@@ -1,3 +0,0 @@
import { MigrationStructure } from '@/hooks/Mapper/mapRootProvider/types.ts';
export default [] as MigrationStructure[];

View File

@@ -1,3 +0,0 @@
import { MigrationStructure } from '@/hooks/Mapper/mapRootProvider/types.ts';
export default [] as MigrationStructure[];

View File

@@ -1,3 +0,0 @@
import { MigrationStructure } from '@/hooks/Mapper/mapRootProvider/types.ts';
export default [] as MigrationStructure[];

View File

@@ -64,19 +64,18 @@ export type KillsWidgetSettings = {
timeRange: number; timeRange: number;
}; };
export type SettingsWithVersion<T> = { export type SettingsWrapper<T> = T;
version: number;
settings: T;
};
export type MapUserSettings = { export type MapUserSettings = {
widgets: SettingsWithVersion<WindowStoreInfo>; migratedFromOld: boolean;
interface: SettingsWithVersion<InterfaceStoredSettings>; version: number;
onTheMap: SettingsWithVersion<OnTheMapSettingsType>; widgets: SettingsWrapper<WindowStoreInfo>;
routes: SettingsWithVersion<RoutesType>; interface: SettingsWrapper<InterfaceStoredSettings>;
localWidget: SettingsWithVersion<LocalWidgetSettings>; onTheMap: SettingsWrapper<OnTheMapSettingsType>;
signaturesWidget: SettingsWithVersion<SignatureSettingsType>; routes: SettingsWrapper<RoutesType>;
killsWidget: SettingsWithVersion<KillsWidgetSettings>; localWidget: SettingsWrapper<LocalWidgetSettings>;
signaturesWidget: SettingsWrapper<SignatureSettingsType>;
killsWidget: SettingsWrapper<KillsWidgetSettings>;
}; };
export type MapUserSettingsStructure = { export type MapUserSettingsStructure = {
@@ -87,7 +86,7 @@ export type WdResponse<T> = T;
export type RemoteAdminSettingsResponse = { default_settings?: string }; export type RemoteAdminSettingsResponse = { default_settings?: string };
export enum MigrationTypes { export enum SettingsTypes {
killsWidget = 'killsWidget', killsWidget = 'killsWidget',
localWidget = 'localWidget', localWidget = 'localWidget',
widgets = 'widgets', widgets = 'widgets',
@@ -100,6 +99,6 @@ export enum MigrationTypes {
export type MigrationFunc = (prev: any) => any; export type MigrationFunc = (prev: any) => any;
export type MigrationStructure = { export type MigrationStructure = {
to: number; to: number;
type: MigrationTypes; up: MigrationFunc;
run: MigrationFunc; down: MigrationFunc;
}; };

View File

@@ -0,0 +1,4 @@
export const STORED_SETTINGS_VERSION = 1;
export const LS_KEY_LEGASY = 'map-user-settings';
export const LS_KEY = 'map-user-settings-v2';

View File

@@ -1,12 +0,0 @@
// TODO IF YOU BUMP VERSION YOU SHOULD ADD MIGRATION!!!
// CHECK assets/js/hooks/Mapper/mapRootProvider/migrations
// FOR EACH TYPE AND EACH VERSION OF SETTINGS SHOULD BE ADDED MIGRATION
export const SETTING_VERSIONS = {
interface: 0,
routes: 0,
localWidget: 0,
onTheMap: 0,
kills: 0,
widgets: 0,
signatures: 0,
};

View File

@@ -2,3 +2,4 @@ export * from './contextStore';
export * from './getQueryVariable'; export * from './getQueryVariable';
export * from './loadTextFile'; export * from './loadTextFile';
export * from './saveToFile'; export * from './saveToFile';
export * from './omit';