Cache mapping status on reload
This commit is contained in:
+46
-6
@@ -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";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user