Cache mapping status on reload

This commit is contained in:
2026-08-05 22:57:06 +02:00
parent 9b1898a588
commit e3caf25823
4 changed files with 143 additions and 12 deletions
+46 -6
View File
@@ -61,6 +61,8 @@ const catalogScreen = document.querySelector(".catalog-screen");
const secondaryPanelToggle = document.querySelector("#secondaryPanelToggle");
const mainWorkspaceToggle = document.querySelector("#mainWorkspaceToggle");
let sidebarUserClosed = false;
let mappingLoadToken = 0;
const mappingCacheKey = "catalog-maker:mapping-cache";
const nativeFetch = window.fetch.bind(window);
window.fetch = (input, init = {}) => {
@@ -175,7 +177,7 @@ manufacturerSelect.addEventListener("change", () => {
syncManufacturerPickerLabel();
closeManufacturerPicker();
if (manufacturerSelect.value) {
loadMappingSources();
loadMappingSources({ checkUrls: false, preferCache: false });
loadProductForSelectedManufacturer(1);
} else {
renderMappingSources({ mapped: false, items: [], message: "Select manufacturer." });
@@ -252,7 +254,7 @@ syncSidebarForViewport();
setTimeout(() => {
if (manufacturerSelect.value) {
loadMappingSources();
loadMappingSources({ checkUrls: false, preferCache: true });
loadProductForSelectedManufacturer(1);
} else {
renderMappingSources({ mapped: false, items: [], message: "Select manufacturer." });
@@ -440,27 +442,39 @@ function syncLanguagePickerLabel() {
languageValue.textContent = option?.textContent || "Select language";
}
async function loadMappingSources() {
async function loadMappingSources({ checkUrls = false, preferCache = false } = {}) {
const manufacturerId = manufacturerSelect.value;
const loadToken = ++mappingLoadToken;
if (!manufacturerId) {
renderMappingSources({ mapped: false, items: [], message: "Select manufacturer." });
return;
}
const cached = preferCache ? readMappingCache(manufacturerId) : null;
if (cached) {
renderMappingSources(cached);
return;
}
setMappingStatus("Loading mapping...", "is-loading");
mappingList.replaceChildren();
try {
const params = new URLSearchParams({ manufacturerId, check: "1" });
const params = new URLSearchParams({ manufacturerId });
if (checkUrls) params.set("check", "1");
const response = await fetch(`/api/catalog-maker/mapping-sources?${params.toString()}`);
const data = await response.json();
if (loadToken !== mappingLoadToken || manufacturerSelect.value !== manufacturerId) return;
if (!response.ok) {
throw new Error(data.message || "Mapping load failed.");
}
renderMappingSources(data);
if (data.mapped && (data.items || []).some((item) => item.enabled)) {
saveMappingCache(manufacturerId, data);
}
} catch (error) {
if (loadToken !== mappingLoadToken || manufacturerSelect.value !== manufacturerId) return;
renderMappingSources({
mapped: false,
items: [],
@@ -469,6 +483,28 @@ async function loadMappingSources() {
}
}
function readMappingCache(manufacturerId) {
try {
const cache = JSON.parse(localStorage.getItem(mappingCacheKey) || "{}");
return cache[String(manufacturerId)] || null;
} catch {
return null;
}
}
function saveMappingCache(manufacturerId, data) {
try {
const cache = JSON.parse(localStorage.getItem(mappingCacheKey) || "{}");
cache[String(manufacturerId)] = {
...data,
cachedAt: new Date().toISOString(),
};
localStorage.setItem(mappingCacheKey, JSON.stringify(cache));
} catch {
// Mapping cache is only a UI convenience. If storage fails, normal loading still works.
}
}
function renderMappingSources(data) {
const items = data.items || [];
@@ -482,11 +518,13 @@ function renderMappingSources(data) {
const enabledCount = items.filter((item) => item.enabled).length;
const failedCount = items.filter((item) => item.enabled && item.health && item.health !== "ok").length;
const testedCount = items.filter((item) => item.enabled && item.health === "ok").length;
const checkedCount = items.filter((item) => item.enabled && item.health).length;
const ready = enabledCount > 0 && failedCount === 0;
const statusText = ready
? `Sources OK ✓ (${testedCount}/${enabledCount})`
: data.message || `Sources problem (${testedCount}/${enabledCount})`;
setMappingStatus(statusText, ready ? "is-ready" : testedCount > 0 ? "is-warning" : "is-missing");
const displayStatusText = ready && !checkedCount ? `Mapping OK (${enabledCount})` : statusText;
setMappingStatus(displayStatusText, ready ? "is-ready" : testedCount > 0 ? "is-warning" : "is-missing");
mappingDetails.open = false;
mappingList.replaceChildren(
@@ -517,6 +555,7 @@ function setMappingStatus(text, stateClass) {
function getMappingHealthText(item) {
if (!item.enabled) return "off";
if (!item.health) return "ready";
if (item.health === "ok") return `${item.httpStatus || 200} OK`;
if (item.health === "missing-url") return "no URL";
if (item.httpStatus) return `${item.httpStatus}`;
@@ -526,6 +565,7 @@ function getMappingHealthText(item) {
function getMappingHealthClass(item) {
if (!item.enabled) return "is-muted";
if (!item.health) return "is-ok";
if (item.health === "ok") return "is-ok";
return "is-bad";
}