From d8f220d825a17c7b411c1ffadf8862aab9c59151 Mon Sep 17 00:00:00 2001 From: Alex Blank Date: Sun, 24 May 2026 19:33:38 +0000 Subject: [PATCH] fix: unify session loading states across pages - Add per-item busy overlay to SessionCard component - Remove full-screen loading overlay from sessions page - Remove loadingAction state, use per-item busy state only - Add handleStart to sessions page for consistency - Add session-card CSS for busy overlay positioning - Both home and sessions pages now use same per-item loading pattern --- apps/web/src/components/session-card.tsx | 7 ++++- apps/web/src/pages/sessions.tsx | 33 +++++++++++------------- apps/web/src/styles.css | 19 ++++++++++++++ 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/apps/web/src/components/session-card.tsx b/apps/web/src/components/session-card.tsx index 00aa0c3..b2ac9dc 100644 --- a/apps/web/src/components/session-card.tsx +++ b/apps/web/src/components/session-card.tsx @@ -75,7 +75,12 @@ export function SessionCard({ const isActive = ["running", "building", "starting", "probing", "pending", "unhealthy"].includes(session.status); return ( -
+
+ {isBusy && ( +
+ +
+ )}
diff --git a/apps/web/src/pages/sessions.tsx b/apps/web/src/pages/sessions.tsx index 11dba2a..3933fae 100644 --- a/apps/web/src/pages/sessions.tsx +++ b/apps/web/src/pages/sessions.tsx @@ -9,6 +9,7 @@ import { type Session, deleteInstance, stopInstance, + startInstance, checkInstanceHealth, recreateInstanceTunnel, } from "../api/sessions"; @@ -38,7 +39,6 @@ export const SessionsPage = () => { const [tunnelHealth, setTunnelHealth] = useState>({}); const [loadingSessionId, setLoadingSessionId] = useState(null); - const [loadingAction, setLoadingAction] = useState(""); const loadSessions = useCallback(async () => { setStatus("loading"); @@ -156,7 +156,6 @@ export const SessionsPage = () => { const handleStop = async (session: Session) => { setLoadingSessionId(session.id); - setLoadingAction("Stopping..."); try { await stopInstance(session.project_id, session.repository_id, session.id); await loadSessions(); @@ -164,13 +163,11 @@ export const SessionsPage = () => { // ignore } finally { setLoadingSessionId(null); - setLoadingAction(""); } }; const handleDelete = async (session: Session) => { setLoadingSessionId(session.id); - setLoadingAction("Deleting..."); try { await deleteInstance(session.project_id, session.repository_id, session.id); setDirtyDeleteSession(null); @@ -189,13 +186,11 @@ export const SessionsPage = () => { } } finally { setLoadingSessionId(null); - setLoadingAction(""); } }; const handleForceDelete = async (session: Session) => { setLoadingSessionId(session.id); - setLoadingAction("Force deleting..."); try { await deleteInstance(session.project_id, session.repository_id, session.id, true); setDirtyDeleteSession(null); @@ -205,13 +200,11 @@ export const SessionsPage = () => { // ignore } finally { setLoadingSessionId(null); - setLoadingAction(""); } }; const handleRecreateTunnel = async (session: Session) => { setLoadingSessionId(session.id); - setLoadingAction("Recreating tunnel..."); try { await recreateInstanceTunnel( session.project_id, @@ -224,7 +217,18 @@ export const SessionsPage = () => { // ignore } finally { setLoadingSessionId(null); - setLoadingAction(""); + } + }; + + const handleStart = async (session: Session) => { + setLoadingSessionId(session.id); + try { + await startInstance(session.project_id, session.repository_id, session.id); + await loadSessions(); + } catch { + // ignore + } finally { + setLoadingSessionId(null); } }; @@ -273,18 +277,11 @@ export const SessionsPage = () => { )} {/* Session List */} -
- {loadingSessionId && ( -
-
- -

{loadingAction}

-
-
- )} +