diff --git a/web/static/js/migration.js b/web/static/js/migration.js index eb3ecbe..3cb0589 100644 --- a/web/static/js/migration.js +++ b/web/static/js/migration.js @@ -8,11 +8,53 @@ import { refreshTemplates } from './templates.js'; // ── Helpers ──────────────────────────────────────────────────────────────── +const _RESULTS_STORAGE_KEY = 'migrator_last_batch_results'; + function getSettings() { try { return JSON.parse(localStorage.getItem('migrator_settings')) || {}; } catch { return {}; } } +function persistLastResults(results) { + try { + sessionStorage.setItem(_RESULTS_STORAGE_KEY, JSON.stringify(results)); + } catch { + // Best-effort only. + } +} + +function loadPersistedResults() { + try { + const raw = sessionStorage.getItem(_RESULTS_STORAGE_KEY); + return raw ? JSON.parse(raw) : null; + } catch { + return null; + } +} + +function buildResultsFromHistory(history) { + if (!history || !history.length) return null; + + const sorted = [...history].sort((a, b) => String(b.timestamp || '').localeCompare(String(a.timestamp || ''))); + const newestTimestamp = sorted[0]?.timestamp; + const recentBatch = sorted.filter(item => item.timestamp === newestTimestamp); + if (!recentBatch.length) return null; + + return { + status: 'completed', + completed_at: newestTimestamp, + results: recentBatch, + summary: { + total: recentBatch.length, + success: recentBatch.filter(r => r.status === 'success').length, + failed: recentBatch.filter(r => r.status === 'failed' || r.status === 'blocked').length, + skipped: recentBatch.filter(r => r.status === 'skipped').length, + dry_run: recentBatch.filter(r => r.status === 'dry_run').length, + }, + recovered_from_history: true, + }; +} + // ── Options modal ────────────────────────────────────────────────────────── export function showOptionsModal(ids) { @@ -230,6 +272,7 @@ export async function pollJob(jobId, onProgress) { if (data.status === 'done' || data.status === 'complete' || data.status === 'completed') { setState('lastMigrationResults', data); + persistLastResults(data); resolve(data); } else if (data.status === 'failed') { reject(new Error('Migration job failed')); @@ -248,16 +291,30 @@ export async function pollJob(jobId, onProgress) { // ── Results view ─────────────────────────────────────────────────────────── -export function renderResults() { +export async function renderResults() { const outlet = document.getElementById('router-outlet'); - const results = state.lastMigrationResults; + let results = state.lastMigrationResults || loadPersistedResults(); + + if (!results) { + try { + const data = await api.migrate.history(); + results = buildResultsFromHistory(data.history || []); + } catch { + results = null; + } + } + + if (results) { + setState('lastMigrationResults', results); + persistLastResults(results); + } if (!results) { outlet.innerHTML = `
📊
No migration results yet
-
Run a migration from the Templates view to see results here.
+
Run a migration from the Templates view to see results here. If templates already exist in DocuSign, use History & Audit to review older runs.
`; return; } @@ -288,6 +345,13 @@ export function renderResults() { + ${results.recovered_from_history ? ` +
+ ℹ️ + These results were recovered from recent migration history after the page state was reset. +
+ ` : ''} +