fix: remove rel=noopener from all session/instance links to enable tab reuse
rel=noopener forces a fresh browsing context, breaking target name matching
and window reference tracking across browsers.
Changes:
- use-instance-actions.ts: track opened tabs in Map, call .focus() on existing
- session-card.tsx: all Open buttons now go through handleOpen callback
- app-shell.tsx: sidebar session links use target='session-{id}' + noreferrer
- workspace-instance-chips.tsx: remove noopener from chip links
- instance-list.tsx: remove noopener from Open links
- WorkspaceDetailPage.tsx: use named target + noreferrer
Quality gates: tsc --noEmit pass, npm run build pass, 80/80 tests pass
This commit is contained in:
@@ -58,11 +58,6 @@ export function SessionCard({
|
||||
const isTerminalOnly =
|
||||
session.tool_type_interfaces?.includes("terminal") &&
|
||||
!session.tool_type_interfaces?.includes("web");
|
||||
const openHref = session.url
|
||||
? session.url
|
||||
: isTerminalOnly
|
||||
? `/instances/${session.id}/terminal`
|
||||
: undefined;
|
||||
const hasTunnelError =
|
||||
!isTerminalOnly && tunnelHealth?.tunnel_status === "unreachable";
|
||||
const hasAppError =
|
||||
@@ -138,13 +133,13 @@ export function SessionCard({
|
||||
)}
|
||||
{session.url && (
|
||||
<p className="session-card-url">
|
||||
<a
|
||||
href={session.url}
|
||||
target={`session-${session.id}`}
|
||||
rel="noopener noreferrer"
|
||||
<button
|
||||
type="button"
|
||||
className="link-button"
|
||||
onClick={() => onOpen?.(session)}
|
||||
>
|
||||
{session.url}
|
||||
</a>
|
||||
</button>
|
||||
</p>
|
||||
)}
|
||||
{session.created_at && (
|
||||
@@ -159,27 +154,15 @@ export function SessionCard({
|
||||
<div className="session-card-actions mobile">
|
||||
{isActive && (
|
||||
<>
|
||||
{openHref ? (
|
||||
<a
|
||||
href={openHref}
|
||||
target={`session-${session.id}`}
|
||||
rel="noopener noreferrer"
|
||||
className="secondary-button mobile-primary"
|
||||
>
|
||||
<Icon name="external" size="sm" />
|
||||
Open
|
||||
</a>
|
||||
) : (
|
||||
<button
|
||||
className="secondary-button mobile-primary"
|
||||
onClick={() => onOpen?.(session)}
|
||||
type="button"
|
||||
disabled={isBusy}
|
||||
>
|
||||
<Icon name="external" size="sm" />
|
||||
Open
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
className="secondary-button mobile-primary"
|
||||
onClick={() => onOpen?.(session)}
|
||||
type="button"
|
||||
disabled={isBusy}
|
||||
>
|
||||
<Icon name="external" size="sm" />
|
||||
Open
|
||||
</button>
|
||||
<button
|
||||
className="ghost-button mobile-more"
|
||||
onClick={() => setShowActionSheet(true)}
|
||||
@@ -216,27 +199,15 @@ export function SessionCard({
|
||||
<div className="session-card-actions">
|
||||
{isActive && (
|
||||
<>
|
||||
{openHref ? (
|
||||
<a
|
||||
href={openHref}
|
||||
target={`session-${session.id}`}
|
||||
rel="noopener noreferrer"
|
||||
className="secondary-button small"
|
||||
>
|
||||
<Icon name="external" size="sm" />
|
||||
<span className="action-label">Open</span>
|
||||
</a>
|
||||
) : (
|
||||
<button
|
||||
className="secondary-button small"
|
||||
onClick={() => onOpen?.(session)}
|
||||
type="button"
|
||||
disabled={isBusy}
|
||||
>
|
||||
<Icon name="external" size="sm" />
|
||||
<span className="action-label">Open</span>
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
className="secondary-button small"
|
||||
onClick={() => onOpen?.(session)}
|
||||
type="button"
|
||||
disabled={isBusy}
|
||||
>
|
||||
<Icon name="external" size="sm" />
|
||||
<span className="action-label">Open</span>
|
||||
</button>
|
||||
|
||||
{!isTerminalOnly && onRecreateTunnel && (
|
||||
<button
|
||||
|
||||
@@ -286,7 +286,7 @@ export const InstanceList = ({
|
||||
: `${API_BASE_URL}${instance.url}`
|
||||
}
|
||||
target={`instance-${instance.id}`}
|
||||
rel="noopener noreferrer"
|
||||
rel="noreferrer"
|
||||
className="secondary-button small"
|
||||
>
|
||||
<Icon name="external" size="sm" />
|
||||
|
||||
@@ -44,7 +44,7 @@ export function WorkspaceInstanceChips({
|
||||
<a
|
||||
href={inst.url}
|
||||
target={`instance-${inst.id}`}
|
||||
rel="noopener noreferrer"
|
||||
rel="noreferrer"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
↗
|
||||
|
||||
Reference in New Issue
Block a user