feat(dashboard): auto-refresh after sync, configurable polling, extra filters

- Detect missed sync completions via last_run.run_id comparison
- Load polling interval from settings (dashboard_poll_seconds, default 5s)
- Add 1min/3min scheduler interval options
- Add 1zi/2zile period filter options
- New Dashboard settings card for polling interval

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-03-17 11:48:29 +00:00
parent 5e01fefd4c
commit dafc2df0d4
5 changed files with 49 additions and 5 deletions

View File

@@ -13,21 +13,32 @@ let _pollInterval = null;
let _lastSyncStatus = null;
let _lastRunId = null;
let _currentRunId = null;
let _pollIntervalMs = 5000; // default, overridden from settings
let _knownLastRunId = null; // track last_run.run_id to detect missed syncs
// ── Init ──────────────────────────────────────────
document.addEventListener('DOMContentLoaded', () => {
document.addEventListener('DOMContentLoaded', async () => {
await initPollInterval();
loadSchedulerStatus();
loadDashOrders();
startSyncPolling();
wireFilterBar();
});
async function initPollInterval() {
try {
const data = await fetchJSON('/api/settings');
const sec = parseInt(data.dashboard_poll_seconds) || 5;
_pollIntervalMs = sec * 1000;
} catch(e) {}
}
// ── Smart Sync Polling ────────────────────────────
function startSyncPolling() {
if (_pollInterval) clearInterval(_pollInterval);
_pollInterval = setInterval(pollSyncStatus, 30000);
_pollInterval = setInterval(pollSyncStatus, _pollIntervalMs);
pollSyncStatus(); // immediate first call
}
@@ -37,6 +48,12 @@ async function pollSyncStatus() {
updateSyncPanel(data);
const isRunning = data.status === 'running';
const wasRunning = _lastSyncStatus === 'running';
// Detect missed sync completions via last_run.run_id change
const newLastRunId = data.last_run?.run_id || null;
const missedSync = !isRunning && !wasRunning && _knownLastRunId && newLastRunId && newLastRunId !== _knownLastRunId;
_knownLastRunId = newLastRunId;
if (isRunning && !wasRunning) {
// Switched to running — speed up polling
clearInterval(_pollInterval);
@@ -44,7 +61,10 @@ async function pollSyncStatus() {
} else if (!isRunning && wasRunning) {
// Sync just completed — slow down and refresh orders
clearInterval(_pollInterval);
_pollInterval = setInterval(pollSyncStatus, 30000);
_pollInterval = setInterval(pollSyncStatus, _pollIntervalMs);
loadDashOrders();
} else if (missedSync) {
// Sync completed while we weren't watching (e.g. auto-sync) — refresh orders
loadDashOrders();
}
_lastSyncStatus = data.status;

View File

@@ -69,6 +69,7 @@ async function loadSettings() {
if (el('settGomagApiShop')) el('settGomagApiShop').value = data.gomag_api_shop || '';
if (el('settGomagDaysBack')) el('settGomagDaysBack').value = data.gomag_order_days_back || '7';
if (el('settGomagLimit')) el('settGomagLimit').value = data.gomag_limit || '100';
if (el('settDashPollSeconds')) el('settDashPollSeconds').value = data.dashboard_poll_seconds || '5';
} catch (err) {
console.error('loadSettings error:', err);
}
@@ -89,6 +90,7 @@ async function saveSettings() {
gomag_api_shop: el('settGomagApiShop')?.value?.trim() || '',
gomag_order_days_back: el('settGomagDaysBack')?.value?.trim() || '7',
gomag_limit: el('settGomagLimit')?.value?.trim() || '100',
dashboard_poll_seconds: el('settDashPollSeconds')?.value?.trim() || '5',
};
try {
const res = await fetch('/api/settings', {