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" && (
- ))} + )})}
)}