Step 6 migration: add JSON backup and restore flows
This commit is contained in:
92
app.js
92
app.js
@@ -33,9 +33,15 @@ const consoleTabs = document.getElementById("consoleTabs");
|
||||
const gameSectionTitle = document.getElementById("gameSectionTitle");
|
||||
const dataModeInfo = document.getElementById("dataModeInfo");
|
||||
const migrateBtn = document.getElementById("migrateBtn");
|
||||
const backupControls = document.getElementById("backupControls");
|
||||
const backupBtn = document.getElementById("backupBtn");
|
||||
const restoreMergeBtn = document.getElementById("restoreMergeBtn");
|
||||
const restoreReplaceBtn = document.getElementById("restoreReplaceBtn");
|
||||
const restoreFileInput = document.getElementById("restoreFileInput");
|
||||
const gamesList = document.getElementById("gamesList");
|
||||
const gameCardTemplate = document.getElementById("gameCardTemplate");
|
||||
let editingGameId = null;
|
||||
let pendingRestoreMode = "merge";
|
||||
|
||||
platformForm.addEventListener("submit", async (event) => {
|
||||
event.preventDefault();
|
||||
@@ -292,6 +298,86 @@ migrateBtn.addEventListener("click", async () => {
|
||||
}
|
||||
});
|
||||
|
||||
backupBtn.addEventListener("click", async () => {
|
||||
if (!apiReachable) {
|
||||
alert("API indisponible. Sauvegarde JSON impossible.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const dump = await apiRequest("/api/backup/export");
|
||||
const blob = new Blob([JSON.stringify(dump, null, 2)], { type: "application/json" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
||||
a.href = url;
|
||||
a.download = `video-games-backup-${stamp}.json`;
|
||||
document.body.append(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
alert("Echec de la sauvegarde JSON.");
|
||||
}
|
||||
});
|
||||
|
||||
restoreMergeBtn.addEventListener("click", () => {
|
||||
pendingRestoreMode = "merge";
|
||||
restoreFileInput.click();
|
||||
});
|
||||
|
||||
restoreReplaceBtn.addEventListener("click", () => {
|
||||
pendingRestoreMode = "replace";
|
||||
restoreFileInput.click();
|
||||
});
|
||||
|
||||
restoreFileInput.addEventListener("change", async (event) => {
|
||||
const input = event.target;
|
||||
const file = input.files && input.files[0] ? input.files[0] : null;
|
||||
input.value = "";
|
||||
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!apiReachable) {
|
||||
alert("API indisponible. Restauration impossible.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const fileText = await file.text();
|
||||
const dump = JSON.parse(fileText);
|
||||
|
||||
if (pendingRestoreMode === "replace") {
|
||||
const confirmed = window.confirm(
|
||||
"Mode remplacement: la base actuelle sera remplacee. Une sauvegarde pre-restore sera creee. Continuer ?",
|
||||
);
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const result = await apiRequest("/api/backup/restore", {
|
||||
method: "POST",
|
||||
body: {
|
||||
mode: pendingRestoreMode,
|
||||
dump,
|
||||
},
|
||||
});
|
||||
|
||||
pendingLocalImport = null;
|
||||
await refreshFromApi(state.selectedBrand, state.selectedConsole);
|
||||
alert(
|
||||
`Restauration terminee (${result.mode}): ${result.insertedGames || 0} jeu(x), ${result.insertedConsoles || 0} console(s).`,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
alert("Echec de la restauration JSON.");
|
||||
}
|
||||
});
|
||||
|
||||
function render() {
|
||||
renderDataMode();
|
||||
renderBrandTabs();
|
||||
@@ -322,6 +408,12 @@ function renderDataMode() {
|
||||
} else {
|
||||
migrateBtn.classList.add("hidden");
|
||||
}
|
||||
|
||||
if (apiReachable) {
|
||||
backupControls.classList.remove("hidden");
|
||||
} else {
|
||||
backupControls.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function renderBrandTabs() {
|
||||
|
||||
Reference in New Issue
Block a user