From cce3fa773acd9cdd7b2681e7c402046d64ad81ce Mon Sep 17 00:00:00 2001 From: Fusion Date: Sun, 24 May 2026 13:02:06 +0200 Subject: [PATCH] feat: hide tunnel UI for terminal sessions and show session metadata Backend: - Add created_at to get_user_sessions response Frontend: - Hide tunnel error badges, probe output, and 'Recreate Tunnel' button for terminal-only sessions - Show session start time (created_at) in active sessions list - Show repository configuration (clone_mode, branch) for each session - Skip health check polling for terminal-only sessions - Update Session type to include created_at field --- apps/api/src/api/tool_instances.py | 1 + apps/web/src/api/sessions.ts | 1 + apps/web/src/pages/sessions.tsx | 27 ++++++++++++++++++++------- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/apps/api/src/api/tool_instances.py b/apps/api/src/api/tool_instances.py index 4e3880b..579eaa4 100644 --- a/apps/api/src/api/tool_instances.py +++ b/apps/api/src/api/tool_instances.py @@ -1437,6 +1437,7 @@ async def get_user_sessions( "url": instance.url, "clone_mode": instance.clone_mode, "branch": instance.branch, + "created_at": instance.created_at.isoformat() if instance.created_at else None, }) return {"sessions": sessions} diff --git a/apps/web/src/api/sessions.ts b/apps/web/src/api/sessions.ts index 04c570d..ae552d6 100644 --- a/apps/web/src/api/sessions.ts +++ b/apps/web/src/api/sessions.ts @@ -29,6 +29,7 @@ export interface Session { probe_status?: string; clone_mode?: string; branch?: string | null; + created_at?: string; } export async function listInstances( diff --git a/apps/web/src/pages/sessions.tsx b/apps/web/src/pages/sessions.tsx index 1ae34f2..66e8c78 100644 --- a/apps/web/src/pages/sessions.tsx +++ b/apps/web/src/pages/sessions.tsx @@ -95,11 +95,12 @@ export const SessionsPage = () => { - // Poll health every 30 seconds for active instances + // Poll health every 30 seconds for active web-enabled instances useEffect(() => { const checkHealth = async () => { const activeSessions = sessions.filter( (s) => ["running", "starting", "unhealthy", "probing"].includes(s.status) + && s.tool_type_interfaces?.includes("web") ); for (const session of activeSessions) { try { @@ -335,13 +336,25 @@ export const SessionsPage = () => {

No active sessions

) : (
- {activeSessions.map((session) => ( + {activeSessions.map((session) => { + const isTerminalOnly = session.tool_type_interfaces?.includes("terminal") && !session.tool_type_interfaces?.includes("web"); + return (

{session.display_name}

{session.tool_type_name} ยท {session.project_name}

+ {session.created_at && ( +

+ Started: {new Date(session.created_at).toLocaleString()} +

+ )} + {session.clone_mode && ( +

+ Repo: {session.clone_mode === "clone" ? `clone (${session.branch || "main"})` : "mount"} +

+ )} {session.url && (

@@ -356,13 +369,13 @@ export const SessionsPage = () => { {session.status === "probing" && ( checking... )} - {tunnelHealth[session.id] && tunnelHealth[session.id].tunnel_status === "unreachable" && ( + {!isTerminalOnly && tunnelHealth[session.id] && tunnelHealth[session.id].tunnel_status === "unreachable" && ( tunnel error )} - {tunnelHealth[session.id] && tunnelHealth[session.id].tunnel_status === "error_response" && ( + {!isTerminalOnly && tunnelHealth[session.id] && tunnelHealth[session.id].tunnel_status === "error_response" && ( app error ({tunnelHealth[session.id].tunnel_status_code}) )} - {tunnelHealth[session.id]?.probe_status && tunnelHealth[session.id]?.probe_status !== "not_applicable" && ( + {!isTerminalOnly && tunnelHealth[session.id]?.probe_status && tunnelHealth[session.id]?.probe_status !== "not_applicable" && (

)} - {tunnelHealth[session.id] && tunnelHealth[session.id].tunnel_status === "unreachable" && ( + {!isTerminalOnly && tunnelHealth[session.id] && tunnelHealth[session.id].tunnel_status === "unreachable" && (
- ))} + )})}
)}