Skip to content

Commit 1e17ad6

Browse files
authored
feat: show error messages for failed files in WebUI (fixes #59) (#60)
1 parent 17c2d01 commit 1e17ad6

2 files changed

Lines changed: 101 additions & 3 deletions

File tree

public/app.js

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -647,11 +647,18 @@ class SubsyncarrPlusClient {
647647
const icon = result.success ? '✓' : '✗';
648648
const className = result.success ? 'success' : 'error';
649649
const duration = (result.duration / 1000).toFixed(1);
650+
const error =
651+
!result.success && result.message
652+
? `<div class="engine-error-message">${this.escapeHtml(result.message)}</div>`
653+
: '';
650654

651655
return `
652656
<div class="engine-result ${className}">
653-
<span>${icon} ${name}</span>
654-
<span class="duration">${duration}s</span>
657+
<div class="engine-result-row">
658+
<span>${icon} ${name}</span>
659+
<span class="duration">${duration}s</span>
660+
</div>
661+
${error}
655662
</div>
656663
`;
657664
})
@@ -813,13 +820,45 @@ class SubsyncarrPlusClient {
813820
'<div class="file-list-empty">No files in this category</div>';
814821
} else {
815822
const html = files
816-
.map((file) => `<div class="file-list-item">${this.cleanFileName(file.file_path)}</div>`)
823+
.map((file) => {
824+
const name = this.cleanFileName(file.file_path);
825+
const errors = category === 'failed' ? this.renderFileErrors(file) : '';
826+
return `<div class="file-list-item">${this.escapeHtml(name)}${errors}</div>`;
827+
})
817828
.join('');
818829
document.getElementById('fileListContent').innerHTML = html;
819830
}
820831

821832
document.getElementById('fileListModal').classList.remove('hidden');
822833
}
834+
835+
// Render the error messages for each engine that failed on a file
836+
renderFileErrors(file) {
837+
let engines;
838+
try {
839+
engines = JSON.parse(file.engines || '{}');
840+
} catch {
841+
return '';
842+
}
843+
844+
const failures = Object.entries(engines).filter(([, result]) => result && result.success === false);
845+
846+
if (failures.length === 0) {
847+
return '';
848+
}
849+
850+
return `<div class="file-list-errors">${failures
851+
.map(([name, result]) => {
852+
const message = result.message || 'Unknown error';
853+
const stderr = result.stderr ? `<pre class="file-error-detail">${this.escapeHtml(result.stderr)}</pre>` : '';
854+
return `<div class="file-error">
855+
<span class="file-error-engine">${this.escapeHtml(name)}</span>
856+
<span class="file-error-message">${this.escapeHtml(message)}</span>
857+
${stderr}
858+
</div>`;
859+
})
860+
.join('')}</div>`;
861+
}
823862
}
824863

825864
// Initialize client when DOM is ready

public/styles.css

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,24 @@ h2 {
319319
.engine-result.error {
320320
background: #fee2e2;
321321
color: #991b1b;
322+
flex-direction: column;
323+
align-items: stretch;
324+
}
325+
326+
.engine-result-row {
327+
display: flex;
328+
align-items: center;
329+
justify-content: space-between;
330+
gap: 8px;
331+
}
332+
333+
.engine-error-message {
334+
margin-top: 4px;
335+
font-size: 12px;
336+
font-family: var(--mono, ui-monospace, monospace);
337+
white-space: pre-wrap;
338+
word-break: break-word;
339+
opacity: 0.9;
322340
}
323341

324342
.duration {
@@ -777,6 +795,47 @@ td {
777795
font-style: italic;
778796
}
779797

798+
.file-list-errors {
799+
margin-top: 8px;
800+
display: flex;
801+
flex-direction: column;
802+
gap: 6px;
803+
}
804+
805+
.file-error {
806+
border-left: 3px solid var(--error);
807+
padding: 4px 0 4px 10px;
808+
}
809+
810+
.file-error-engine {
811+
display: inline-block;
812+
font-size: 11px;
813+
font-weight: 600;
814+
text-transform: uppercase;
815+
letter-spacing: 0.03em;
816+
color: var(--error);
817+
margin-right: 8px;
818+
}
819+
820+
.file-error-message {
821+
font-size: 13px;
822+
color: var(--text);
823+
word-break: break-word;
824+
}
825+
826+
.file-error-detail {
827+
margin: 6px 0 0;
828+
padding: 8px;
829+
background: var(--background);
830+
border-radius: 4px;
831+
font-size: 12px;
832+
white-space: pre-wrap;
833+
word-break: break-word;
834+
max-height: 160px;
835+
overflow-y: auto;
836+
color: var(--text-secondary);
837+
}
838+
780839
/* Mobile responsive */
781840
@media (max-width: 768px) {
782841
.container {

0 commit comments

Comments
 (0)