diff --git a/web/static/css/modals.css b/web/static/css/modals.css
index 9e52c20..432a7bf 100644
--- a/web/static/css/modals.css
+++ b/web/static/css/modals.css
@@ -118,6 +118,7 @@
.progress-template-row {
display: flex;
align-items: center;
+ flex-wrap: wrap;
gap: 10px;
padding: 8px 12px;
background: var(--ecru);
@@ -126,6 +127,16 @@
}
.progress-template-name { flex: 1; font-weight: 500; }
.progress-template-status { font-size: 16px; flex-shrink: 0; }
+.progress-template-error {
+ flex-basis: 100%;
+ font-size: 11px;
+ color: var(--error, #c0392b);
+ margin-top: -4px;
+ padding-left: 2px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
/* ── Project switcher modal ── */
.project-list {
diff --git a/web/static/js/migration.js b/web/static/js/migration.js
index 47fe536..32099d2 100644
--- a/web/static/js/migration.js
+++ b/web/static/js/migration.js
@@ -162,15 +162,36 @@ async function _startMigration(ids, wrapper) {
const statusEl = row.querySelector('.progress-template-status');
if (!statusEl) return;
statusEl.className = 'progress-template-status';
- if (r.status === 'success') statusEl.textContent = r.action === 'created' ? '✅' : r.action === 'dry_run' ? '🔍' : '✏️';
+ if (r.status === 'success') statusEl.textContent = r.action === 'created' ? '✅' : r.action === 'dry_run' ? '🔍' : '✏️';
else if (r.status === 'skipped') statusEl.textContent = '⏭';
else if (r.status === 'blocked') statusEl.textContent = '🚫';
- else statusEl.textContent = '❌';
+ else statusEl.textContent = '❌';
+
+ if (r.status === 'blocked' || r.status === 'error' || r.status === 'failed') {
+ const msg = r.error || (r.blockers||[])[0] || 'Migration failed';
+ let hint = row.querySelector('.progress-template-error');
+ if (!hint) {
+ hint = document.createElement('div');
+ hint.className = 'progress-template-error';
+ row.appendChild(hint);
+ }
+ hint.textContent = msg;
+ }
});
});
// Migration done — show "View Results" button
+ const allResults = (jobData.results || []);
+ const failCount = allResults.filter(r => r.status === 'blocked' || r.status === 'error' || r.status === 'failed').length;
document.getElementById('prog-label') && (document.getElementById('prog-label').textContent = 'Done!');
+
+ if (failCount > 0) {
+ const hint = document.createElement('div');
+ hint.style.cssText = 'font-size:12px;color:var(--text-muted);margin-top:10px;text-align:center';
+ hint.textContent = `${failCount} template${failCount > 1 ? 's' : ''} had issues — select View Results for details.`;
+ body.appendChild(hint);
+ }
+
footer.innerHTML = `