add health import
This commit is contained in:
@@ -1557,6 +1557,100 @@
|
||||
}
|
||||
}
|
||||
|
||||
function initHealthImportStatus() {
|
||||
const panel = document.querySelector("[data-health-import-status]");
|
||||
if (!panel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const progressWrap = panel.querySelector("[data-health-progress-wrap]");
|
||||
const progress = panel.querySelector("[data-health-progress-bar]");
|
||||
const progressText = panel.querySelector("[data-health-progress-text]");
|
||||
const lastImport = panel.querySelector("[data-health-last-import]");
|
||||
const lastMessage = panel.querySelector("[data-health-last-message]");
|
||||
let timer = null;
|
||||
|
||||
const formatDuration = seconds => {
|
||||
const rounded = Math.max(0, Math.round(Number(seconds) || 0));
|
||||
if (rounded < 60) {
|
||||
return `${rounded} s`;
|
||||
}
|
||||
|
||||
return `${Math.ceil(rounded / 60)} min`;
|
||||
};
|
||||
|
||||
const render = status => {
|
||||
const done = Math.max(0, Number(status.progress_done || 0));
|
||||
const total = Math.max(0, Number(status.progress_total || 0));
|
||||
const percent = total > 0 ? Math.min(100, Math.round((done / total) * 100)) : 0;
|
||||
|
||||
if (progress) {
|
||||
progress.value = String(percent);
|
||||
progress.textContent = `${percent}%`;
|
||||
}
|
||||
|
||||
if (progressWrap) {
|
||||
progressWrap.dataset.progressDone = String(done);
|
||||
progressWrap.dataset.progressTotal = String(total);
|
||||
}
|
||||
|
||||
if (lastImport) {
|
||||
lastImport.textContent = status.last_import_at ? new Date(status.last_import_at).toLocaleString("de-DE") : "-";
|
||||
}
|
||||
|
||||
if (lastMessage) {
|
||||
lastMessage.textContent = status.last_message || "-";
|
||||
}
|
||||
|
||||
if (progressText) {
|
||||
if (status.last_status === "running") {
|
||||
let eta = "wird berechnet";
|
||||
const started = Date.parse(status.started_at || "");
|
||||
if (started && done > 0 && total > done) {
|
||||
const elapsed = (Date.now() - started) / 1000;
|
||||
eta = formatDuration((elapsed / done) * (total - done));
|
||||
}
|
||||
progressText.textContent = `Import läuft: ${done} von ${total} verarbeitet. Restzeit ca. ${eta}.`;
|
||||
return;
|
||||
}
|
||||
|
||||
if (status.last_status === "error") {
|
||||
progressText.textContent = `${status.last_message || "Import fehlgeschlagen."} Derselbe Export kann erneut gesendet werden und wird idempotent übernommen.`;
|
||||
return;
|
||||
}
|
||||
|
||||
progressText.textContent = status.last_message || "Noch kein Import gelaufen.";
|
||||
}
|
||||
};
|
||||
|
||||
const initialDone = progressWrap ? Number(progressWrap.dataset.progressDone || 0) : 0;
|
||||
const initialTotal = progressWrap ? Number(progressWrap.dataset.progressTotal || 0) : 0;
|
||||
render({ progress_done: initialDone, progress_total: initialTotal });
|
||||
|
||||
const refresh = async () => {
|
||||
try {
|
||||
const response = await fetch("/api/health/status", { credentials: "same-origin" });
|
||||
if (!response.ok) {
|
||||
return;
|
||||
}
|
||||
const data = await response.json();
|
||||
if (!data || !data.ok || !data.status) {
|
||||
return;
|
||||
}
|
||||
render(data.status);
|
||||
if (data.status.last_status !== "running" && timer !== null) {
|
||||
window.clearInterval(timer);
|
||||
timer = null;
|
||||
}
|
||||
} catch (error) {
|
||||
// Status polling is best-effort; the import itself is server-side.
|
||||
}
|
||||
};
|
||||
|
||||
refresh();
|
||||
timer = window.setInterval(refresh, 3500);
|
||||
}
|
||||
|
||||
function csrfToken() {
|
||||
return document.querySelector('meta[name="csrf-token"]')?.getAttribute("content") || "";
|
||||
}
|
||||
@@ -1888,6 +1982,7 @@
|
||||
initDashboardCharts();
|
||||
initDashboardExperience();
|
||||
initOptionsPanels();
|
||||
initHealthImportStatus();
|
||||
initSportTypeManager();
|
||||
initPwaShell();
|
||||
initPullToRefresh();
|
||||
|
||||
Reference in New Issue
Block a user