Fix: log viewer wipes itself due to auto-reload on deploy done
Two bugs causing 'can't see why deploy failed': - showLog() called window.location.reload() on the SSE 'done' event, wiping the log panel before the user could read it. - For already-finished deploys, SSE would immediately fire 'done' and reload, showing logs for < 1 second. Fix: - showLog() now fetches the deploy via REST first. If done, it renders the stored log directly (no SSE). If still running, it streams via SSE and closes without reloading when done. - Added onerror fallback: re-fetches the log via REST if SSE drops. - Status badge (green/red) updates inline instead of triggering reload. - Page now auto-opens the latest deploy log on load so the failure reason is visible immediately without any clicking. https://claude.ai/code/session_01FKCW3FDjNFj6jve4niMFXH
This commit is contained in:
parent
0180f37c31
commit
d322cc3ce1
1 changed files with 61 additions and 14 deletions
|
|
@ -213,6 +213,8 @@ pub async fn app_detail(
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let latest_deploy_id = deploys.first().map(|d| d.id.as_str()).unwrap_or("");
|
||||||
|
|
||||||
let mut deploy_rows = String::new();
|
let mut deploy_rows = String::new();
|
||||||
for d in &deploys {
|
for d in &deploys {
|
||||||
let sha_short = d.sha.as_deref()
|
let sha_short = d.sha.as_deref()
|
||||||
|
|
@ -268,7 +270,7 @@ pub async fn app_detail(
|
||||||
<tbody>{deploy_rows}</tbody>
|
<tbody>{deploy_rows}</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div id="log-panel" style="display:none;margin-top:16px">
|
<div id="log-panel" style="display:none;margin-top:16px">
|
||||||
<h2 style="margin-bottom:8px">Build Log</h2>
|
<h2 id="log-title" style="margin-bottom:8px">Build Log</h2>
|
||||||
<pre id="log-out"></pre>
|
<pre id="log-out"></pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -299,20 +301,64 @@ pub async fn app_detail(
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const APP_ID = '{app_id}';
|
const APP_ID = '{app_id}';
|
||||||
|
|
||||||
|
// Auto-open the latest deploy log on page load.
|
||||||
|
window.addEventListener('DOMContentLoaded', () => {{
|
||||||
|
const latest = '{latest_deploy_id}';
|
||||||
|
if (latest) showLog(latest);
|
||||||
|
}});
|
||||||
|
|
||||||
async function deploy() {{
|
async function deploy() {{
|
||||||
const r = await fetch('/api/apps/' + APP_ID + '/deploy', {{method:'POST'}});
|
const r = await fetch('/api/apps/' + APP_ID + '/deploy', {{method:'POST'}});
|
||||||
if (r.ok) {{ const d = await r.json(); showLog(d.id); }}
|
if (r.ok) {{ const d = await r.json(); showLog(d.id); }}
|
||||||
else alert('Deploy failed: ' + await r.text());
|
else alert('Deploy failed: ' + await r.text());
|
||||||
}}
|
}}
|
||||||
function showLog(deployId) {{
|
async function showLog(deployId) {{
|
||||||
const panel = document.getElementById('log-panel');
|
const panel = document.getElementById('log-panel');
|
||||||
const out = document.getElementById('log-out');
|
const out = document.getElementById('log-out');
|
||||||
|
const title = document.getElementById('log-title');
|
||||||
panel.style.display = 'block';
|
panel.style.display = 'block';
|
||||||
out.textContent = '';
|
out.textContent = 'Loading…';
|
||||||
panel.scrollIntoView({{behavior:'smooth'}});
|
panel.scrollIntoView({{behavior:'smooth'}});
|
||||||
|
|
||||||
|
// Fetch current deploy state first.
|
||||||
|
const r = await fetch('/api/deploys/' + deployId);
|
||||||
|
if (!r.ok) {{ out.textContent = 'Could not load deploy ' + deployId; return; }}
|
||||||
|
const deploy = await r.json();
|
||||||
|
|
||||||
|
title.textContent = 'Build Log — ' + deploy.status;
|
||||||
|
title.style.color = deploy.status === 'success' ? '#4ade80'
|
||||||
|
: deploy.status === 'failed' ? '#f87171' : '#fb923c';
|
||||||
|
|
||||||
|
// Already finished — just render the stored log, no SSE needed.
|
||||||
|
if (deploy.status === 'success' || deploy.status === 'failed') {{
|
||||||
|
out.textContent = deploy.log || '(no output captured)';
|
||||||
|
out.scrollTop = out.scrollHeight;
|
||||||
|
return;
|
||||||
|
}}
|
||||||
|
|
||||||
|
// Still running — stream updates via SSE.
|
||||||
|
out.textContent = '';
|
||||||
const es = new EventSource('/api/deploys/' + deployId + '/logs');
|
const es = new EventSource('/api/deploys/' + deployId + '/logs');
|
||||||
es.onmessage = e => {{ out.textContent += e.data; out.scrollTop = out.scrollHeight; }};
|
es.onmessage = e => {{
|
||||||
es.addEventListener('done', () => {{ es.close(); window.location.reload(); }});
|
out.textContent += e.data;
|
||||||
|
out.scrollTop = out.scrollHeight;
|
||||||
|
}};
|
||||||
|
es.addEventListener('done', e => {{
|
||||||
|
es.close();
|
||||||
|
title.textContent = 'Build Log — ' + e.data;
|
||||||
|
title.style.color = e.data === 'success' ? '#4ade80' : '#f87171';
|
||||||
|
}});
|
||||||
|
es.onerror = () => {{
|
||||||
|
es.close();
|
||||||
|
// Fallback: re-fetch the finished log.
|
||||||
|
fetch('/api/deploys/' + deployId)
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(d => {{
|
||||||
|
out.textContent = d.log || out.textContent;
|
||||||
|
title.textContent = 'Build Log — ' + d.status;
|
||||||
|
}});
|
||||||
|
}};
|
||||||
}}
|
}}
|
||||||
async function setEnv() {{
|
async function setEnv() {{
|
||||||
const key = document.getElementById('ev-key').value.trim();
|
const key = document.getElementById('ev-key').value.trim();
|
||||||
|
|
@ -331,15 +377,16 @@ pub async fn app_detail(
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}}
|
}}
|
||||||
</script>"#,
|
</script>"#,
|
||||||
name = app.name,
|
name = app.name,
|
||||||
repo = app.repo_url,
|
repo = app.repo_url,
|
||||||
branch = app.branch,
|
branch = app.branch,
|
||||||
port = app.port,
|
port = app.port,
|
||||||
host = host,
|
host = host,
|
||||||
app_id = app.id,
|
app_id = app.id,
|
||||||
secret = app.webhook_secret,
|
secret = app.webhook_secret,
|
||||||
deploy_rows = deploy_rows,
|
deploy_rows = deploy_rows,
|
||||||
env_rows = env_rows,
|
env_rows = env_rows,
|
||||||
|
latest_deploy_id = latest_deploy_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(Html(page(&app.name, &body)))
|
Ok(Html(page(&app.name, &body)))
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue