fix(Map): Added migration mechanism

This commit is contained in:
DanSylvest
2025-09-28 09:29:42 +03:00
parent f89cd5f44f
commit 5c8753fb96
17 changed files with 155 additions and 66 deletions

View File

@@ -1,11 +1,10 @@
import { NodeSelectionMouseHandler } from '@/hooks/Mapper/components/contexts/types.ts'; import { NodeSelectionMouseHandler } from '@/hooks/Mapper/components/contexts/types.ts';
import { SESSION_KEY } from '@/hooks/Mapper/constants.ts';
import { PingData, SolarSystemConnection, SolarSystemRawType } from '@/hooks/Mapper/types'; import { PingData, SolarSystemConnection, SolarSystemRawType } from '@/hooks/Mapper/types';
import { MapHandlers, OutCommand, OutCommandHandler } from '@/hooks/Mapper/types/mapHandlers.ts'; import { MapHandlers, OutCommand, OutCommandHandler } from '@/hooks/Mapper/types/mapHandlers.ts';
import { ctxManager } from '@/hooks/Mapper/utils/contextManager.ts'; import { ctxManager } from '@/hooks/Mapper/utils/contextManager.ts';
import type { PanelPosition } from '@reactflow/core'; import type { PanelPosition } from '@reactflow/core';
import clsx from 'clsx'; import clsx from 'clsx';
import { ForwardedRef, forwardRef, MouseEvent, useCallback, useEffect, useMemo } from 'react'; import { ForwardedRef, forwardRef, MouseEvent, useCallback, useEffect, useMemo, useRef } from 'react';
import ReactFlow, { import ReactFlow, {
Background, Background,
Edge, Edge,
@@ -33,19 +32,9 @@ import {
import { getBehaviorForTheme } from './helpers/getThemeBehavior'; import { getBehaviorForTheme } from './helpers/getThemeBehavior';
import { useEdgesState, useMapHandlers, useNodesState, useUpdateNodes } from './hooks'; import { useEdgesState, useMapHandlers, useNodesState, useUpdateNodes } from './hooks';
import { useBackgroundVars } from './hooks/useBackgroundVars'; import { useBackgroundVars } from './hooks/useBackgroundVars';
import { OnMapAddSystemCallback, OnMapSelectionChange } from './map.types'; import { MapViewport, OnMapAddSystemCallback, OnMapSelectionChange } from './map.types';
import type { Viewport } from '@reactflow/core/dist/esm/types';
const DEFAULT_VIEW_PORT = { zoom: 1, x: 0, y: 0 }; import { usePrevious } from 'primereact/hooks';
const getViewPortFromStore = () => {
const restored = localStorage.getItem(SESSION_KEY.viewPort);
if (!restored) {
return { ...DEFAULT_VIEW_PORT };
}
return JSON.parse(restored);
};
const initialNodes: Node<SolarSystemRawType>[] = [ const initialNodes: Node<SolarSystemRawType>[] = [
// { // {
@@ -88,6 +77,7 @@ interface MapCompProps {
onConnectionInfoClick?(e: SolarSystemConnection): void; onConnectionInfoClick?(e: SolarSystemConnection): void;
onAddSystem?: OnMapAddSystemCallback; onAddSystem?: OnMapAddSystemCallback;
onSelectionContextMenu?: NodeSelectionMouseHandler; onSelectionContextMenu?: NodeSelectionMouseHandler;
onChangeViewport?: (viewport: MapViewport) => void;
minimapClasses?: string; minimapClasses?: string;
isShowMinimap?: boolean; isShowMinimap?: boolean;
onSystemContextMenu: (event: MouseEvent<Element>, systemId: string) => void; onSystemContextMenu: (event: MouseEvent<Element>, systemId: string) => void;
@@ -99,6 +89,7 @@ interface MapCompProps {
pings: PingData[]; pings: PingData[];
minimapPlacement?: PanelPosition; minimapPlacement?: PanelPosition;
localShowShipName?: boolean; localShowShipName?: boolean;
defaultViewport?: Viewport;
} }
const MapComp = ({ const MapComp = ({
@@ -119,19 +110,25 @@ const MapComp = ({
pings, pings,
minimapPlacement = 'bottom-right', minimapPlacement = 'bottom-right',
localShowShipName = false, localShowShipName = false,
onChangeViewport,
defaultViewport,
}: MapCompProps) => { }: MapCompProps) => {
const { getNodes } = useReactFlow(); const { getNodes, setViewport } = useReactFlow();
const [nodes, , onNodesChange] = useNodesState<Node<SolarSystemRawType>>(initialNodes); const [nodes, , onNodesChange] = useNodesState<Node<SolarSystemRawType>>(initialNodes);
const [edges, , onEdgesChange] = useEdgesState<Edge<SolarSystemConnection>>(initialEdges); const [edges, , onEdgesChange] = useEdgesState<Edge<SolarSystemConnection>>(initialEdges);
useMapHandlers(refn, onSelectionChange); useMapHandlers(refn, onSelectionChange);
useUpdateNodes(nodes); useUpdateNodes(nodes);
const { handleRootContext, ...rootCtxProps } = useContextMenuRootHandlers({ onAddSystem }); const { handleRootContext, ...rootCtxProps } = useContextMenuRootHandlers({ onAddSystem });
const { handleConnectionContext, ...connectionCtxProps } = useContextMenuConnectionHandlers(); const { handleConnectionContext, ...connectionCtxProps } = useContextMenuConnectionHandlers();
const { update } = useMapState(); const { update } = useMapState();
const { variant, gap, size, color } = useBackgroundVars(theme); const { variant, gap, size, color } = useBackgroundVars(theme);
const { isPanAndDrag, nodeComponent, connectionMode } = getBehaviorForTheme(theme || 'default'); const { isPanAndDrag, nodeComponent, connectionMode } = getBehaviorForTheme(theme || 'default');
const refVars = useRef({ onChangeViewport });
refVars.current = { onChangeViewport };
const nodeTypes = useMemo(() => { const nodeTypes = useMemo(() => {
return { return {
custom: nodeComponent, custom: nodeComponent,
@@ -187,9 +184,13 @@ const MapComp = ({
[onSelectionChange], [onSelectionChange],
); );
const handleMoveEnd: OnMoveEnd = (_, viewport) => { const handleMoveEnd: OnMoveEnd = useCallback((_, viewport) => {
localStorage.setItem(SESSION_KEY.viewPort, JSON.stringify(viewport)); // @ts-ignore
}; refVars.current.onChangeViewport?.(viewport);
}, []);
// eslint-disable-next-line no-console
console.log('JOipP', `defaultViewport`, defaultViewport);
const handleNodesChange = useCallback( const handleNodesChange = useCallback(
(changes: NodeChange[]) => { (changes: NodeChange[]) => {
@@ -218,6 +219,19 @@ const MapComp = ({
})); }));
}, [showKSpaceBG, isThickConnections, pings, update, localShowShipName]); }, [showKSpaceBG, isThickConnections, pings, update, localShowShipName]);
const prevViewport = usePrevious(defaultViewport);
useEffect(() => {
if (defaultViewport == null) {
return;
}
if (prevViewport == null) {
return;
}
setViewport(defaultViewport);
}, [defaultViewport, prevViewport, setViewport]);
return ( return (
<> <>
<div <div
@@ -232,7 +246,7 @@ const MapComp = ({
onConnect={onConnect} onConnect={onConnect}
// TODO we need save into session all of this // TODO we need save into session all of this
// and on any action do either // and on any action do either
defaultViewport={getViewPortFromStore()} defaultViewport={defaultViewport}
edgeTypes={edgeTypes} edgeTypes={edgeTypes}
nodeTypes={nodeTypes} nodeTypes={nodeTypes}
connectionMode={connectionMode} connectionMode={connectionMode}

View File

@@ -10,3 +10,5 @@ export type OnMapSelectionChange = (event: {
}) => void; }) => void;
export type OnMapAddSystemCallback = (props: { coordinates: XYPosition | null }) => void; export type OnMapAddSystemCallback = (props: { coordinates: XYPosition | null }) => void;
export type MapViewport = { zoom: 1; x: 0; y: 0 };

View File

@@ -6,6 +6,7 @@ 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'; import { applyMigrations } from '@/hooks/Mapper/mapRootProvider/migrations';
import { createDefaultStoredSettings } from '@/hooks/Mapper/mapRootProvider/helpers/createDefaultStoredSettings.ts';
export const ImportExport = () => { export const ImportExport = () => {
const { const {
@@ -25,7 +26,7 @@ export const ImportExport = () => {
try { try {
// INFO: WE NOT SUPPORT MIGRATIONS FOR OLD FILES AND Clipboard // INFO: WE NOT SUPPORT MIGRATIONS FOR OLD FILES AND Clipboard
const parsed = parseMapUserSettings(text); const parsed = parseMapUserSettings(text);
if (applySettings(applyMigrations(parsed))) { if (applySettings(applyMigrations(parsed) || createDefaultStoredSettings())) {
toast.current?.show({ toast.current?.show({
severity: 'success', severity: 'success',
summary: 'Import', summary: 'Import',

View File

@@ -3,7 +3,7 @@ import { useCallback, useEffect, useRef, useState } from 'react';
import { Toast } from 'primereact/toast'; import { Toast } from 'primereact/toast';
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 { createDefaultStoredSettings } from '@/hooks/Mapper/mapRootProvider/helpers/createDefaultStoredSettings.ts';
import { callToastSuccess } from '@/hooks/Mapper/helpers'; 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';
@@ -29,7 +29,7 @@ export const ServerSettings = () => {
} }
if (res?.default_settings == null) { if (res?.default_settings == null) {
applySettings(createDefaultWidgetSettings()); applySettings(createDefaultStoredSettings());
return; return;
} }
@@ -38,7 +38,7 @@ export const ServerSettings = () => {
applySettings(applyMigrations(JSON.parse(res.default_settings))); 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(createDefaultStoredSettings());
} }
}, [applySettings, outCommand]); }, [applySettings, outCommand]);

View File

@@ -14,7 +14,7 @@ import { Connections } from '@/hooks/Mapper/components/mapRootContent/components
import { ContextMenuSystemMultiple, useContextMenuSystemMultipleHandlers } from '../contexts/ContextMenuSystemMultiple'; import { ContextMenuSystemMultiple, useContextMenuSystemMultipleHandlers } from '../contexts/ContextMenuSystemMultiple';
import { getSystemById } from '@/hooks/Mapper/helpers'; import { getSystemById } from '@/hooks/Mapper/helpers';
import { Commands } from '@/hooks/Mapper/types/mapHandlers.ts'; import { Commands } from '@/hooks/Mapper/types/mapHandlers.ts';
import { Node, useReactFlow, XYPosition } from 'reactflow'; import { Node, useReactFlow, Viewport, XYPosition } from 'reactflow';
import { useCommandsSystems } from '@/hooks/Mapper/mapRootProvider/hooks/api'; import { useCommandsSystems } from '@/hooks/Mapper/mapRootProvider/hooks/api';
import { emitMapEvent, useMapEventListener } from '@/hooks/Mapper/events'; import { emitMapEvent, useMapEventListener } from '@/hooks/Mapper/events';
@@ -48,7 +48,7 @@ export const MapWrapper = () => {
linkSignatureToSystem, linkSignatureToSystem,
systemSignatures, systemSignatures,
}, },
storedSettings: { interfaceSettings, settingsLocal }, storedSettings: { interfaceSettings, settingsLocal, mapSettings, mapSettingsUpdate },
} = useMapRootState(); } = useMapRootState();
const { const {
@@ -83,8 +83,17 @@ export const MapWrapper = () => {
systems, systems,
systemSignatures, systemSignatures,
deleteSystems, deleteSystems,
mapSettingsUpdate,
}); });
ref.current = { selectedConnections, selectedSystems, systemContextProps, systems, systemSignatures, deleteSystems }; ref.current = {
selectedConnections,
selectedSystems,
systemContextProps,
systems,
systemSignatures,
deleteSystems,
mapSettingsUpdate,
};
useMapEventListener(event => { useMapEventListener(event => {
runCommand(event); runCommand(event);
@@ -121,6 +130,10 @@ export const MapWrapper = () => {
[update], [update],
); );
const handleChangeViewport = useCallback((viewport: Viewport) => {
ref.current.mapSettingsUpdate({ viewport });
}, []);
const handleCommand: OutCommandHandler = useCallback( const handleCommand: OutCommandHandler = useCallback(
event => { event => {
switch (event.type) { switch (event.type) {
@@ -259,6 +272,7 @@ export const MapWrapper = () => {
onConnectionInfoClick={handleConnectionDbClick} onConnectionInfoClick={handleConnectionDbClick}
onSystemContextMenu={handleSystemContextMenu} onSystemContextMenu={handleSystemContextMenu}
onSelectionContextMenu={handleSystemMultipleContext} onSelectionContextMenu={handleSystemMultipleContext}
onChangeViewport={handleChangeViewport}
minimapClasses={minimapClasses} minimapClasses={minimapClasses}
isShowMinimap={showMinimap} isShowMinimap={showMinimap}
showKSpaceBG={isShowKSpace} showKSpaceBG={isShowKSpace}
@@ -270,6 +284,7 @@ export const MapWrapper = () => {
onAddSystem={onAddSystem} onAddSystem={onAddSystem}
minimapPlacement={minimapPosition} minimapPlacement={minimapPosition}
localShowShipName={settingsLocal.showShipName} localShowShipName={settingsLocal.showShipName}
defaultViewport={mapSettings.viewport}
/> />
{openSettings != null && ( {openSettings != null && (

View File

@@ -23,12 +23,14 @@ import {
InterfaceStoredSettings, InterfaceStoredSettings,
KillsWidgetSettings, KillsWidgetSettings,
LocalWidgetSettings, LocalWidgetSettings,
MapSettings,
MapUserSettings, MapUserSettings,
OnTheMapSettingsType, OnTheMapSettingsType,
RoutesType, RoutesType,
} from '@/hooks/Mapper/mapRootProvider/types.ts'; } from '@/hooks/Mapper/mapRootProvider/types.ts';
import { import {
DEFAULT_KILLS_WIDGET_SETTINGS, DEFAULT_KILLS_WIDGET_SETTINGS,
DEFAULT_MAP_SETTINGS,
DEFAULT_ON_THE_MAP_SETTINGS, DEFAULT_ON_THE_MAP_SETTINGS,
DEFAULT_ROUTES_SETTINGS, DEFAULT_ROUTES_SETTINGS,
DEFAULT_WIDGET_LOCAL_SETTINGS, DEFAULT_WIDGET_LOCAL_SETTINGS,
@@ -127,6 +129,8 @@ export interface MapRootContextProps {
settingsOnTheMapUpdate: Dispatch<SetStateAction<OnTheMapSettingsType>>; settingsOnTheMapUpdate: Dispatch<SetStateAction<OnTheMapSettingsType>>;
settingsKills: KillsWidgetSettings; settingsKills: KillsWidgetSettings;
settingsKillsUpdate: Dispatch<SetStateAction<KillsWidgetSettings>>; settingsKillsUpdate: Dispatch<SetStateAction<KillsWidgetSettings>>;
mapSettings: MapSettings;
mapSettingsUpdate: Dispatch<SetStateAction<MapSettings>>;
isReady: boolean; isReady: boolean;
hasOldSettings: boolean; hasOldSettings: boolean;
getSettingsForExport(): string | undefined; getSettingsForExport(): string | undefined;
@@ -172,6 +176,8 @@ const MapRootContext = createContext<MapRootContextProps>({
settingsOnTheMapUpdate: () => null, settingsOnTheMapUpdate: () => null,
settingsKills: DEFAULT_KILLS_WIDGET_SETTINGS, settingsKills: DEFAULT_KILLS_WIDGET_SETTINGS,
settingsKillsUpdate: () => null, settingsKillsUpdate: () => null,
mapSettings: DEFAULT_MAP_SETTINGS,
mapSettingsUpdate: () => null,
isReady: false, isReady: false,
hasOldSettings: false, hasOldSettings: false,
getSettingsForExport: () => '', getSettingsForExport: () => '',

View File

@@ -3,6 +3,7 @@ import {
InterfaceStoredSettings, InterfaceStoredSettings,
KillsWidgetSettings, KillsWidgetSettings,
LocalWidgetSettings, LocalWidgetSettings,
MapSettings,
MiniMapPlacement, MiniMapPlacement,
OnTheMapSettingsType, OnTheMapSettingsType,
PingsPlacement, PingsPlacement,
@@ -53,6 +54,10 @@ export const DEFAULT_KILLS_WIDGET_SETTINGS: KillsWidgetSettings = {
timeRange: 4, timeRange: 4,
}; };
export const DEFAULT_MAP_SETTINGS: MapSettings = {
viewport: { zoom: 1, x: 0, y: 0 },
};
export const getDefaultWidgetProps = () => ({ export const getDefaultWidgetProps = () => ({
visible: STORED_VISIBLE_WIDGETS_DEFAULT, visible: STORED_VISIBLE_WIDGETS_DEFAULT,
windows: DEFAULT_WIDGETS, windows: DEFAULT_WIDGETS,

View File

@@ -1,6 +1,7 @@
import { MapUserSettings, SettingsTypes, SettingsWrapper } 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_MAP_SETTINGS,
DEFAULT_ON_THE_MAP_SETTINGS, DEFAULT_ON_THE_MAP_SETTINGS,
DEFAULT_ROUTES_SETTINGS, DEFAULT_ROUTES_SETTINGS,
DEFAULT_WIDGET_LOCAL_SETTINGS, DEFAULT_WIDGET_LOCAL_SETTINGS,
@@ -15,7 +16,7 @@ export const createWidgetSettings = <T>(settings: T) => {
return settings; return settings;
}; };
export const createDefaultWidgetSettings = (): MapUserSettings => { export const createDefaultStoredSettings = (): MapUserSettings => {
return { return {
version: STORED_SETTINGS_VERSION, version: STORED_SETTINGS_VERSION,
migratedFromOld: true, migratedFromOld: true,
@@ -26,6 +27,7 @@ export const createDefaultWidgetSettings = (): MapUserSettings => {
onTheMap: createWidgetSettings(DEFAULT_ON_THE_MAP_SETTINGS), onTheMap: createWidgetSettings(DEFAULT_ON_THE_MAP_SETTINGS),
signaturesWidget: createWidgetSettings(DEFAULT_SIGNATURE_SETTINGS), signaturesWidget: createWidgetSettings(DEFAULT_SIGNATURE_SETTINGS),
interface: createWidgetSettings(STORED_INTERFACE_DEFAULT_VALUES), interface: createWidgetSettings(STORED_INTERFACE_DEFAULT_VALUES),
map: createWidgetSettings(DEFAULT_MAP_SETTINGS),
}; };
}; };
@@ -47,5 +49,7 @@ export const getDefaultSettingsByType = (type: SettingsTypes): SettingsWrapper<a
return createWidgetSettings(DEFAULT_SIGNATURE_SETTINGS); return createWidgetSettings(DEFAULT_SIGNATURE_SETTINGS);
case SettingsTypes.interface: case SettingsTypes.interface:
return createWidgetSettings(STORED_INTERFACE_DEFAULT_VALUES); return createWidgetSettings(STORED_INTERFACE_DEFAULT_VALUES);
case SettingsTypes.map:
return createWidgetSettings(DEFAULT_MAP_SETTINGS);
} }
}; };

View File

@@ -5,7 +5,7 @@ import {
MapUserSettingsStructure, MapUserSettingsStructure,
RemoteAdminSettingsResponse, RemoteAdminSettingsResponse,
} from '@/hooks/Mapper/mapRootProvider/types.ts'; } from '@/hooks/Mapper/mapRootProvider/types.ts';
import { createDefaultWidgetSettings } from '@/hooks/Mapper/mapRootProvider/helpers/createDefaultWidgetSettings.ts'; import { createDefaultStoredSettings } from '@/hooks/Mapper/mapRootProvider/helpers/createDefaultStoredSettings.ts';
import { applyMigrations } from '@/hooks/Mapper/mapRootProvider/migrations'; import { applyMigrations } from '@/hooks/Mapper/mapRootProvider/migrations';
interface UseActualizeRemoteMapSettingsProps { interface UseActualizeRemoteMapSettingsProps {
@@ -37,14 +37,14 @@ export const useActualizeRemoteMapSettings = ({
} }
if (res?.default_settings == null) { if (res?.default_settings == null) {
applySettings(createDefaultWidgetSettings()); applySettings(createDefaultStoredSettings());
return; return;
} }
try { try {
applySettings(applyMigrations(JSON.parse(res.default_settings))); applySettings(applyMigrations(JSON.parse(res.default_settings)));
} catch (error) { } catch (error) {
applySettings(createDefaultWidgetSettings()); applySettings(createDefaultStoredSettings());
} }
}, [outCommand]); }, [outCommand]);

View File

@@ -6,7 +6,7 @@ import { useSettingsValueAndSetter } from '@/hooks/Mapper/mapRootProvider/hooks/
import fastDeepEqual from 'fast-deep-equal'; 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 { createDefaultStoredSettings } from '@/hooks/Mapper/mapRootProvider/helpers/createDefaultStoredSettings.ts';
import { applyMigrations, extractData } 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'; import { LS_KEY, LS_KEY_LEGASY } from '@/hooks/Mapper/mapRootProvider/version.ts';
@@ -85,13 +85,20 @@ export const useMapUserSettings = ({ map_slug }: MapRootData, outCommand: OutCom
'killsWidget', 'killsWidget',
); );
const [windowsSettings, setWindowsSettings] = useSettingsValueAndSetter( const [windowsSettings, windowsSettingsUpdate] = useSettingsValueAndSetter(
mapUserSettings, mapUserSettings,
setMapUserSettings, setMapUserSettings,
map_slug, map_slug,
'widgets', 'widgets',
); );
const [mapSettings, mapSettingsUpdate] = useSettingsValueAndSetter(
mapUserSettings,
setMapUserSettings,
map_slug,
'map',
);
// HERE we MUST work with migrations // HERE we MUST work with migrations
useEffect(() => { useEffect(() => {
if (isReady) { if (isReady) {
@@ -151,7 +158,7 @@ export const useMapUserSettings = ({ map_slug }: MapRootData, outCommand: OutCom
}, []); }, []);
const resetSettings = useCallback(() => { const resetSettings = useCallback(() => {
applySettings(createDefaultWidgetSettings()); applySettings(createDefaultStoredSettings());
}, [applySettings]); }, [applySettings]);
return { return {
@@ -171,7 +178,9 @@ export const useMapUserSettings = ({ map_slug }: MapRootData, outCommand: OutCom
settingsKills, settingsKills,
settingsKillsUpdate, settingsKillsUpdate,
windowsSettings, windowsSettings,
setWindowsSettings, windowsSettingsUpdate,
mapSettings,
mapSettingsUpdate,
getSettingsForExport, getSettingsForExport,
applySettings, applySettings,

View File

@@ -15,17 +15,17 @@ export type ToggleWidgetVisibility = (widgetId: WidgetsIds) => void;
interface UseStoreWidgetsProps { interface UseStoreWidgetsProps {
windowsSettings: WindowStoreInfo; windowsSettings: WindowStoreInfo;
setWindowsSettings: Dispatch<SetStateAction<WindowStoreInfo>>; windowsSettingsUpdate: Dispatch<SetStateAction<WindowStoreInfo>>;
} }
export const useStoreWidgets = ({ windowsSettings, setWindowsSettings }: UseStoreWidgetsProps) => { export const useStoreWidgets = ({ windowsSettings, windowsSettingsUpdate }: UseStoreWidgetsProps) => {
const ref = useRef({ windowsSettings, setWindowsSettings }); const ref = useRef({ windowsSettings, windowsSettingsUpdate });
ref.current = { windowsSettings, setWindowsSettings }; ref.current = { windowsSettings, windowsSettingsUpdate };
const updateWidgetSettings: WindowsManagerOnChange = useCallback(({ windows, viewPort }) => { const updateWidgetSettings: WindowsManagerOnChange = useCallback(({ windows, viewPort }) => {
const { setWindowsSettings } = ref.current; const { windowsSettingsUpdate } = ref.current;
setWindowsSettings(({ visible /*, windows*/ }: WindowStoreInfo) => { windowsSettingsUpdate(({ visible /*, windows*/ }: WindowStoreInfo) => {
return { return {
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
windows: DEFAULT_WIDGETS.map(({ content, ...x }) => { windows: DEFAULT_WIDGETS.map(({ content, ...x }) => {
@@ -43,9 +43,9 @@ export const useStoreWidgets = ({ windowsSettings, setWindowsSettings }: UseStor
}, []); }, []);
const toggleWidgetVisibility: ToggleWidgetVisibility = useCallback(widgetId => { const toggleWidgetVisibility: ToggleWidgetVisibility = useCallback(widgetId => {
const { setWindowsSettings } = ref.current; const { windowsSettingsUpdate } = ref.current;
setWindowsSettings(({ visible, windows, ...x }) => { windowsSettingsUpdate(({ visible, windows, ...x }) => {
const isCheckedPrev = visible.includes(widgetId); const isCheckedPrev = visible.includes(widgetId);
if (!isCheckedPrev) { if (!isCheckedPrev) {
const maxZIndex = Math.max(...windows.map(w => w.zIndex)); const maxZIndex = Math.max(...windows.map(w => w.zIndex));
@@ -70,7 +70,7 @@ export const useStoreWidgets = ({ windowsSettings, setWindowsSettings }: UseStor
}); });
}, []); }, []);
const resetWidgets = useCallback(() => ref.current.setWindowsSettings(getDefaultWidgetProps()), []); const resetWidgets = useCallback(() => ref.current.windowsSettingsUpdate(getDefaultWidgetProps()), []);
return { return {
windowsSettings, windowsSettings,

View File

@@ -1,6 +1,7 @@
import { MapUserSettingsStructure } from '@/hooks/Mapper/mapRootProvider/types.ts'; import { MapUserSettingsStructure } from '@/hooks/Mapper/mapRootProvider/types.ts';
import { STORED_SETTINGS_VERSION } from '@/hooks/Mapper/mapRootProvider/version.ts'; import { STORED_SETTINGS_VERSION } from '@/hooks/Mapper/mapRootProvider/version.ts';
import { migrations } from '@/hooks/Mapper/mapRootProvider/migrations/index.ts'; import { migrations } from '@/hooks/Mapper/mapRootProvider/migrations/index.ts';
import { createDefaultStoredSettings } from '@/hooks/Mapper/mapRootProvider/helpers/createDefaultStoredSettings.ts';
export 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);
@@ -28,9 +29,23 @@ export const applyMigrations = (mapSettings: any) => {
return; return;
} }
// Upgrade const cmVersion = currentMapSettings.version || 0;
if (direction > 0) {
const preparedMigrations = migrations.sort((a, b) => a.to - b.to).filter(x => x.to <= STORED_SETTINGS_VERSION); // downgrade
// INFO: when we downgrading - if diff between >= 1 it means was major version
if (direction < 0) {
// If was minor version - we do nothing
if (Math.abs(direction) < 1) {
return currentMapSettings;
}
// if was major version - we set default settings
return createDefaultStoredSettings();
}
const preparedMigrations = migrations
.sort((a, b) => a.to - b.to)
.filter(x => x.to > cmVersion && x.to <= STORED_SETTINGS_VERSION);
for (const migration of preparedMigrations) { for (const migration of preparedMigrations) {
const { to, up } = migration; const { to, up } = migration;
@@ -39,18 +54,5 @@ export const applyMigrations = (mapSettings: any) => {
currentMapSettings = { ...next, version: to, migratedFromOld: true }; 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; return currentMapSettings;
}; };

View File

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

View File

@@ -7,9 +7,4 @@ export const to_1: MigrationStructure = {
return { ...acc, [k]: prev[k].settings }; return { ...acc, [k]: prev[k].settings };
}, Object.create(null)); }, 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

@@ -0,0 +1,28 @@
import { MigrationStructure } from '@/hooks/Mapper/mapRootProvider/types.ts';
const IN_V1_STORE_KEY = 'viewPort';
const IN_V1_DEFAULT_VIEWPORT = { zoom: 1, x: 0, y: 0 };
export const to_2: MigrationStructure = {
to: 2,
up: (prev: any) => {
const restored = localStorage.getItem(IN_V1_STORE_KEY);
let current = IN_V1_DEFAULT_VIEWPORT;
if (restored != null) {
try {
current = JSON.parse(restored);
} catch (err) {
// do nothing
}
localStorage.removeItem(IN_V1_STORE_KEY);
}
return {
...prev,
map: {
viewport: current,
},
};
},
};

View File

@@ -64,6 +64,12 @@ export type KillsWidgetSettings = {
timeRange: number; timeRange: number;
}; };
export type MapViewPort = { zoom: number; x: number; y: number };
export type MapSettings = {
viewport: MapViewPort;
};
export type SettingsWrapper<T> = T; export type SettingsWrapper<T> = T;
export type MapUserSettings = { export type MapUserSettings = {
@@ -76,6 +82,7 @@ export type MapUserSettings = {
localWidget: SettingsWrapper<LocalWidgetSettings>; localWidget: SettingsWrapper<LocalWidgetSettings>;
signaturesWidget: SettingsWrapper<SignatureSettingsType>; signaturesWidget: SettingsWrapper<SignatureSettingsType>;
killsWidget: SettingsWrapper<KillsWidgetSettings>; killsWidget: SettingsWrapper<KillsWidgetSettings>;
map: SettingsWrapper<MapSettings>;
}; };
export type MapUserSettingsStructure = { export type MapUserSettingsStructure = {
@@ -94,11 +101,11 @@ export enum SettingsTypes {
onTheMap = 'onTheMap', onTheMap = 'onTheMap',
signaturesWidget = 'signaturesWidget', signaturesWidget = 'signaturesWidget',
interface = 'interface', interface = 'interface',
map = 'map',
} }
export type MigrationFunc = (prev: any) => any; export type MigrationFunc = (prev: any) => any;
export type MigrationStructure = { export type MigrationStructure = {
to: number; to: number;
up: MigrationFunc; up: MigrationFunc;
down: MigrationFunc;
}; };

View File

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