diff --git a/apps/web/src/components/app-shell.tsx b/apps/web/src/components/app-shell.tsx
index 6664a02..54afad1 100644
--- a/apps/web/src/components/app-shell.tsx
+++ b/apps/web/src/components/app-shell.tsx
@@ -2,6 +2,7 @@ import { Link, NavLink, Outlet, useLocation } from "react-router-dom";
import type { Session } from "../api/sessions";
import { useTheme } from "../hooks/use-theme";
+import { openSession } from "../utils/open-session";
import { useAuth } from "../state/auth";
import { useSessions } from "../state/sessions";
import { useMobileViewport } from "../hooks/use-mobile-viewport";
@@ -33,19 +34,6 @@ const NAV_ITEMS: {
const SessionItem = ({ session }: { session: Session }) => {
const isRunning = session.status === "running";
- // Determine the link target:
- // - Web tools open their tunnel URL
- // - Terminal tools open the terminal page
- // - Everything else falls back to the project page
- const hasTerminal = session.tool_type_interfaces.includes("terminal");
- const hasWeb = session.tool_type_interfaces.includes("web");
- const href =
- session.url && hasWeb
- ? session.url
- : hasTerminal
- ? `/instances/${session.id}/terminal`
- : `/projects/${session.project_id}`;
-
const contextName = session.workspace_name || session.repository_name;
const tooltipParts = [
session.display_name,
@@ -56,10 +44,9 @@ const SessionItem = ({ session }: { session: Session }) => {
tooltipParts.push(`(${session.status})`);
return (
- openSession(session)}
className="nav-item session-item"
title={tooltipParts.join(" · ")}
>
@@ -76,7 +63,7 @@ const SessionItem = ({ session }: { session: Session }) => {
{session.tool_type_name} · {session.project_name}
-
+
);
};
diff --git a/apps/web/src/components/features/project/ProjectListItem.tsx b/apps/web/src/components/features/project/ProjectListItem.tsx
index ca94413..496901c 100644
--- a/apps/web/src/components/features/project/ProjectListItem.tsx
+++ b/apps/web/src/components/features/project/ProjectListItem.tsx
@@ -5,6 +5,7 @@ import { Icon } from "../../icon";
import type { Session } from "../../../api/sessions";
import type { IconName } from "../../../utils/icons";
import type { ProjectWithRepos, RepositorySummary } from "../../../types";
+import { openSession } from "../../../utils/open-session";
interface ProjectListItemProps {
project: ProjectWithRepos;
@@ -13,6 +14,7 @@ interface ProjectListItemProps {
onDelete: () => void;
onConfirmDelete: () => void;
onCancelDelete: () => void;
+ onAddRepository?: () => void;
sessions: Session[];
}
@@ -23,6 +25,7 @@ export const ProjectListItem = ({
onDelete,
onConfirmDelete,
onCancelDelete,
+ onAddRepository,
sessions,
}: ProjectListItemProps) => {
return (
@@ -75,17 +78,23 @@ export const ProjectListItem = ({
- {project.repositories.length === 0 ? (
-
No repositories.
- ) : (
- project.repositories.map((repo) => (
-
- ))
+ {project.repositories.map((repo) => (
+
+ ))}
+ {onAddRepository && (
+
)}
@@ -169,22 +178,10 @@ function ProjectRepoItem({
}
function SessionToolLink({ session }: { session: Session }) {
- const hasTerminal = session.tool_type_interfaces.includes("terminal");
- const hasWeb = session.tool_type_interfaces.includes("web");
- const href =
- session.url && hasWeb
- ? session.url
- : hasTerminal
- ? `/instances/${session.id}/terminal`
- : `/projects/${session.project_id}`;
-
- const isExternal = href.startsWith("http");
-
return (
- openSession(session)}
className="workspace-tool-link"
title={`${session.display_name} (${session.status})`}
>
@@ -195,6 +192,6 @@ function SessionToolLink({ session }: { session: Session }) {
{session.display_name || session.tool_type_name}
-
+
);
}
diff --git a/apps/web/src/hooks/use-instance-actions.ts b/apps/web/src/hooks/use-instance-actions.ts
index ce2dc61..ac650f6 100644
--- a/apps/web/src/hooks/use-instance-actions.ts
+++ b/apps/web/src/hooks/use-instance-actions.ts
@@ -1,4 +1,4 @@
-import { useState, useCallback, useRef } from "react";
+import { useState, useCallback } from "react";
import {
stopInstance,
deleteInstance,
@@ -8,6 +8,7 @@ import {
} from "../api/sessions";
import type { Session } from "../api/sessions";
import { useSessions } from "../state/sessions";
+import { openSession } from "../utils/open-session";
interface UseInstanceActionsOptions {
onRefresh: () => Promise;
@@ -37,27 +38,9 @@ export function useInstanceActions(
null,
);
const [dirtyDeleteFiles, setDirtyDeleteFiles] = useState([]);
- const tabRefs = useRef