fix(map): restore saved styles as inactive drafts
This commit is contained in:
@@ -3,8 +3,10 @@ import {
|
||||
buildDynamicStyleTemplate,
|
||||
buildStyleVariables,
|
||||
getDefaultCustomBreaks,
|
||||
hydrateStoredLayerStyleStates,
|
||||
resolveLayerStyle,
|
||||
requiresStyleApply,
|
||||
selectStoredLayerStyles,
|
||||
validateStyleConfig,
|
||||
} from "./styleEditorUtils";
|
||||
|
||||
@@ -104,4 +106,25 @@ describe("styleEditorUtils", () => {
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("hydrates workspace settings as inactive drafts", () => {
|
||||
const storedPipeStyle = {
|
||||
...createDefaultLayerStyleState("pipes").styleConfig,
|
||||
property: "flow",
|
||||
showLabels: false,
|
||||
};
|
||||
const restored = hydrateStoredLayerStyleStates(
|
||||
{
|
||||
version: 2,
|
||||
layers: { pipes: storedPipeStyle },
|
||||
},
|
||||
2,
|
||||
);
|
||||
|
||||
expect(restored.find((state) => state.layerId === "pipes")?.styleConfig).toEqual(
|
||||
storedPipeStyle,
|
||||
);
|
||||
expect(restored.every((state) => !state.isActive)).toBe(true);
|
||||
expect(selectStoredLayerStyles(restored).pipes).toEqual(storedPipeStyle);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,11 +4,14 @@ import { calculateClassification } from "@utils/breaksClassification";
|
||||
import { parseColor } from "@utils/parseColor";
|
||||
|
||||
import {
|
||||
createDefaultLayerStyleStates,
|
||||
GRADIENT_PALETTES,
|
||||
RAINBOW_PALETTES,
|
||||
SINGLE_COLOR_PALETTES,
|
||||
} from "./styleEditorPresets";
|
||||
import type {
|
||||
DefaultLayerStyleId,
|
||||
LayerStyleState,
|
||||
ResolvedLayerStyle,
|
||||
StyleConfig,
|
||||
StyleValidationResult,
|
||||
@@ -232,6 +235,44 @@ export const validateStyleConfig = (styleConfig: StyleConfig): StyleValidationRe
|
||||
return { valid: errors.length === 0, errors };
|
||||
};
|
||||
|
||||
export const hydrateStoredLayerStyleStates = (
|
||||
document: unknown,
|
||||
expectedVersion: number,
|
||||
): LayerStyleState[] => {
|
||||
const defaults = createDefaultLayerStyleStates();
|
||||
if (!document || typeof document !== "object") return defaults;
|
||||
|
||||
const storedDocument = document as {
|
||||
version?: number;
|
||||
layers?: Partial<Record<DefaultLayerStyleId, StyleConfig>>;
|
||||
};
|
||||
if (storedDocument.version !== expectedVersion || !storedDocument.layers) {
|
||||
return defaults;
|
||||
}
|
||||
|
||||
return defaults.map((state) => {
|
||||
const stored = storedDocument.layers?.[state.layerId as DefaultLayerStyleId];
|
||||
if (!stored || !validateStyleConfig(stored).valid) return state;
|
||||
return {
|
||||
...state,
|
||||
styleConfig: {
|
||||
...stored,
|
||||
customBreaks: [...(stored.customBreaks || [])],
|
||||
customColors: [...(stored.customColors || [])],
|
||||
},
|
||||
legendConfig: { ...state.legendConfig, property: stored.property },
|
||||
isActive: false,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
export const selectStoredLayerStyles = (states: LayerStyleState[]) =>
|
||||
Object.fromEntries(
|
||||
states
|
||||
.filter((state) => state.layerId === "junctions" || state.layerId === "pipes")
|
||||
.map((state) => [state.layerId, state.styleConfig]),
|
||||
) as Partial<Record<DefaultLayerStyleId, StyleConfig>>;
|
||||
|
||||
export const requiresStyleApply = (
|
||||
applied: StyleConfig | undefined,
|
||||
draft: StyleConfig,
|
||||
|
||||
@@ -20,11 +20,13 @@ import {
|
||||
buildStyleVariables,
|
||||
getDefaultCustomBreaks,
|
||||
getDefaultCustomColors,
|
||||
hydrateStoredLayerStyleStates,
|
||||
normalizeCustomBreaks,
|
||||
requiresStyleApply,
|
||||
resolveDimensions,
|
||||
resolveLayerStyle,
|
||||
resolveStyleColors,
|
||||
selectStoredLayerStyles,
|
||||
validateStyleConfig,
|
||||
} from "./styleEditorUtils";
|
||||
import type {
|
||||
@@ -885,23 +887,10 @@ export const useStyleEditor = ({
|
||||
try {
|
||||
const raw = window.localStorage.getItem(storageKey);
|
||||
if (raw) {
|
||||
const document = JSON.parse(raw) as {
|
||||
version?: number;
|
||||
layers?: Partial<Record<DefaultLayerStyleId, StyleConfig>>;
|
||||
};
|
||||
if (document.version === STYLE_STORAGE_VERSION && document.layers) {
|
||||
restored = createDefaultLayerStyleStates().map((state) => {
|
||||
if (!isDefaultLayerId(state.layerId)) return state;
|
||||
const stored = document.layers?.[state.layerId];
|
||||
if (!stored || !validateStyleConfig(stored).valid) return state;
|
||||
return {
|
||||
...state,
|
||||
styleConfig: cloneStyleConfig(stored),
|
||||
legendConfig: { ...state.legendConfig, property: stored.property },
|
||||
isActive: true,
|
||||
};
|
||||
});
|
||||
}
|
||||
restored = hydrateStoredLayerStyleStates(
|
||||
JSON.parse(raw),
|
||||
STYLE_STORAGE_VERSION,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("Restore layer styles failed", error);
|
||||
@@ -910,19 +899,14 @@ export const useStyleEditor = ({
|
||||
setLayerStyleStates(restored);
|
||||
const restoredSelection = restored.find((state) => state.layerId === "junctions");
|
||||
if (restoredSelection) setStyleConfig(cloneStyleConfig(restoredSelection.styleConfig));
|
||||
restored
|
||||
.filter((state) => state.isActive && isDefaultLayerId(state.layerId))
|
||||
.forEach((state) => syncAuxiliaryLayers(state.layerId as DefaultLayerStyleId, state.styleConfig));
|
||||
syncAuxiliaryLayers("junctions", null);
|
||||
syncAuxiliaryLayers("pipes", null);
|
||||
setPersistenceReady(true);
|
||||
}, [setLayerStyleStates, storageKey, syncAuxiliaryLayers]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!persistenceReady) return;
|
||||
const layers = Object.fromEntries(
|
||||
layerStyleStates
|
||||
.filter((state) => state.isActive && isDefaultLayerId(state.layerId))
|
||||
.map((state) => [state.layerId, state.styleConfig]),
|
||||
);
|
||||
const layers = selectStoredLayerStyles(layerStyleStates);
|
||||
try {
|
||||
window.localStorage.setItem(
|
||||
storageKey,
|
||||
|
||||
Reference in New Issue
Block a user