From b83de1e743f91d5b96423b93a9d23283bd38be0c Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 19 Mar 2026 12:10:12 +0000 Subject: [PATCH] Fix usability issues: redirect on missing app and back-to-dashboard after deploy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - app_detail now redirects to / instead of 404 when app is not found (handles case where app was removed while user was on the detail page) - Add a "← Dashboard" button in the log panel that appears once a deployment finishes (both success and failed), giving the user a clear path back to the main screen https://claude.ai/code/session_01FKCW3FDjNFj6jve4niMFXH --- server/src/routes/ui.rs | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/server/src/routes/ui.rs b/server/src/routes/ui.rs index aa2d66d..6b975af 100644 --- a/server/src/routes/ui.rs +++ b/server/src/routes/ui.rs @@ -1,7 +1,7 @@ use axum::{ extract::{Path, State}, http::StatusCode, - response::Html, + response::{Html, IntoResponse, Redirect, Response}, }; use crate::{ @@ -189,13 +189,16 @@ pub async fn index(State(s): State) -> Result, StatusCode pub async fn app_detail( State(s): State, Path(app_id): Path, -) -> Result, StatusCode> { - let app = sqlx::query_as::<_, App>("SELECT * FROM apps WHERE id = ?") +) -> Response { + let app = match sqlx::query_as::<_, App>("SELECT * FROM apps WHERE id = ?") .bind(&app_id) .fetch_optional(&s.db) .await - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)? - .ok_or(StatusCode::NOT_FOUND)?; + { + Err(_) => return StatusCode::INTERNAL_SERVER_ERROR.into_response(), + Ok(None) => return Redirect::to("/").into_response(), + Ok(Some(a)) => a, + }; let deploys = sqlx::query_as::<_, Deploy>( "SELECT * FROM deploys WHERE app_id = ? ORDER BY created_at DESC LIMIT 15", @@ -270,7 +273,12 @@ pub async fn app_detail( {deploy_rows} @@ -334,6 +342,7 @@ pub async fn app_detail( if (deploy.status === 'success' || deploy.status === 'failed') {{ out.textContent = deploy.log || '(no output captured)'; out.scrollTop = out.scrollHeight; + document.getElementById('back-btn').style.display = 'inline-block'; return; }} @@ -348,6 +357,7 @@ pub async fn app_detail( es.close(); title.textContent = 'Build Log — ' + e.data; title.style.color = e.data === 'success' ? '#4ade80' : '#f87171'; + document.getElementById('back-btn').style.display = 'inline-block'; }}); es.onerror = () => {{ es.close(); @@ -389,5 +399,5 @@ pub async fn app_detail( latest_deploy_id = latest_deploy_id, ); - Ok(Html(page(&app.name, &body))) + Html(page(&app.name, &body)).into_response() }