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
+50 -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 = {}) => {
const url = typeof input === "string" ? input : input.url;
@@ -169,7 +171,7 @@ manufacturerSelect.addEventListener("change", () => {
syncManufacturerPickerLabel();
closeManufacturerPicker();
if (manufacturerSelect.value) {
loadMappingSources();
loadMappingSources({ checkUrls: false, preferCache: false });
loadProductForSelectedManufacturer(1);
}
else {
@@ -252,7 +254,7 @@ loadDatabaseMode();
syncSidebarForViewport();
setTimeout(() => {
if (manufacturerSelect.value) {
loadMappingSources();
loadMappingSources({ checkUrls: false, preferCache: true });
loadProductForSelectedManufacturer(1);
}
else {
@@ -419,24 +421,38 @@ function syncLanguagePickerLabel() {
const option = languageSelect.selectedOptions[0];
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: [],
@@ -444,6 +460,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 || [];
if (!data.mapped || !items.length) {
@@ -455,11 +493,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(...items.map((item) => {
const row = document.createElement("div");
@@ -483,6 +523,8 @@ 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")
@@ -496,6 +538,8 @@ 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";