fix: remove features string from window.open to enable tab reuse

window.open(url, name, 'noopener,noreferrer') with a non-empty features
string forces a new popup window and ignores the name for tab reuse.
Remove the third parameter so the browser focuses existing named tabs.

Quality gates: tsc --noEmit pass, npm run build pass, 80/80 tests pass
This commit is contained in:
Developer
2026-06-09 12:18:28 +00:00
parent 486f3cbc44
commit e5e29aca49
3 changed files with 223 additions and 222 deletions
@@ -138,7 +138,11 @@ export function SessionCard({
)}
{session.url && (
<p className="session-card-url">
<a href={session.url} target={`session-${session.id}`} rel="noopener noreferrer">
<a
href={session.url}
target={`session-${session.id}`}
rel="noopener noreferrer"
>
{session.url}
</a>
</p>
@@ -11,7 +11,10 @@ import {
} from "../../../api/sessions";
import type { ToolType } from "../../../api/tool-types";
import { CreateSessionForm } from "../session/create-session-form";
import { listConfigProfiles, type ConfigProfile } from "../../../api/config-profiles";
import {
listConfigProfiles,
type ConfigProfile,
} from "../../../api/config-profiles";
import { listSSHKeys, type SSHKey } from "../../../api/ssh-keys";
import { useEventContext } from "../../../state/events";
@@ -307,120 +310,117 @@ export const InstanceList = ({
)}
{instance.status !== "running" && (
<>
{profileSelectInstanceId === instance.id ? (
<div className="inline-profile-select">
<select
value={selectedProfileForAction}
onChange={(e) =>
setSelectedProfileForAction(e.target.value)
}
>
<option value="">Default (none)</option>
{configProfiles.map((p) => (
<option key={p.id} value={p.id}>
{p.name}
</option>
))}
</select>
<div
style={{
display: "flex",
flexWrap: "wrap",
gap: "0.25rem",
marginTop: "0.25rem",
}}
>
{sshKeys.map((key) => (
<label
key={key.id}
className="checkbox-label"
{profileSelectInstanceId === instance.id ? (
<div className="inline-profile-select">
<select
value={selectedProfileForAction}
onChange={(e) =>
setSelectedProfileForAction(e.target.value)
}
>
<option value="">Default (none)</option>
{configProfiles.map((p) => (
<option key={p.id} value={p.id}>
{p.name}
</option>
))}
</select>
<div
style={{
fontSize: "0.75rem",
display: "flex",
alignItems: "center",
flexWrap: "wrap",
gap: "0.25rem",
marginTop: "0.25rem",
}}
>
<input
type="checkbox"
checked={selectedSshKeyIdsForAction.includes(
key.id,
)}
onChange={(e) => {
if (e.target.checked) {
setSelectedSshKeyIdsForAction(
(prev) => [...prev, key.id],
);
} else {
setSelectedSshKeyIdsForAction(
(prev) =>
prev.filter(
(id) =>
id !== key.id,
),
);
}
}}
/>
{key.name}
</label>
))}
</div>
<button
className="primary-button small"
onClick={() =>
void handleStart(
instance.id,
selectedProfileForAction || undefined,
selectedSshKeyIdsForAction.length > 0
? selectedSshKeyIdsForAction
: undefined,
)
}
type="button"
disabled={busyInstanceId === instance.id}
>
<Icon name="play" size="sm" />
Start
</button>
<button
className="ghost-button small"
onClick={() => {
setProfileSelectInstanceId(null);
setSelectedProfileForAction("");
setSelectedSshKeyIdsForAction([]);
}}
type="button"
disabled={busyInstanceId === instance.id}
>
Cancel
</button>
</div>
) : (
<button
className="secondary-button small"
onClick={() => {
const toolType = toolTypes.find(
(t) => t.id === instance.tool_type_id,
);
if (toolType) {
void loadConfigProfiles(toolType.id);
}
setProfileSelectInstanceId(instance.id);
setSelectedProfileForAction(
instance.selected_config_profile_id || "",
);
setSelectedSshKeyIdsForAction(
instance.ssh_key_ids || [],
);
}}
type="button"
disabled={busyInstanceId === instance.id}
>
<Icon name="play" size="sm" />
Start
</button>
)}
{sshKeys.map((key) => (
<label
key={key.id}
className="checkbox-label"
style={{
fontSize: "0.75rem",
display: "flex",
alignItems: "center",
gap: "0.25rem",
}}
>
<input
type="checkbox"
checked={selectedSshKeyIdsForAction.includes(
key.id,
)}
onChange={(e) => {
if (e.target.checked) {
setSelectedSshKeyIdsForAction((prev) => [
...prev,
key.id,
]);
} else {
setSelectedSshKeyIdsForAction((prev) =>
prev.filter((id) => id !== key.id),
);
}
}}
/>
{key.name}
</label>
))}
</div>
<button
className="primary-button small"
onClick={() =>
void handleStart(
instance.id,
selectedProfileForAction || undefined,
selectedSshKeyIdsForAction.length > 0
? selectedSshKeyIdsForAction
: undefined,
)
}
type="button"
disabled={busyInstanceId === instance.id}
>
<Icon name="play" size="sm" />
Start
</button>
<button
className="ghost-button small"
onClick={() => {
setProfileSelectInstanceId(null);
setSelectedProfileForAction("");
setSelectedSshKeyIdsForAction([]);
}}
type="button"
disabled={busyInstanceId === instance.id}
>
Cancel
</button>
</div>
) : (
<button
className="secondary-button small"
onClick={() => {
const toolType = toolTypes.find(
(t) => t.id === instance.tool_type_id,
);
if (toolType) {
void loadConfigProfiles(toolType.id);
}
setProfileSelectInstanceId(instance.id);
setSelectedProfileForAction(
instance.selected_config_profile_id || "",
);
setSelectedSshKeyIdsForAction(
instance.ssh_key_ids || [],
);
}}
type="button"
disabled={busyInstanceId === instance.id}
>
<Icon name="play" size="sm" />
Start
</button>
)}
</>
)}
{instance.status === "running" && (
@@ -455,119 +455,116 @@ export const InstanceList = ({
<Icon name="stop" size="sm" />
</button>
)}
{profileSelectInstanceId === instance.id ? (
<div className="inline-profile-select">
<select
value={selectedProfileForAction}
onChange={(e) =>
setSelectedProfileForAction(e.target.value)
}
>
<option value="">Default (none)</option>
{configProfiles.map((p) => (
<option key={p.id} value={p.id}>
{p.name}
</option>
))}
</select>
<div
style={{
display: "flex",
flexWrap: "wrap",
gap: "0.25rem",
marginTop: "0.25rem",
}}
>
{sshKeys.map((key) => (
<label
key={key.id}
className="checkbox-label"
{profileSelectInstanceId === instance.id ? (
<div className="inline-profile-select">
<select
value={selectedProfileForAction}
onChange={(e) =>
setSelectedProfileForAction(e.target.value)
}
>
<option value="">Default (none)</option>
{configProfiles.map((p) => (
<option key={p.id} value={p.id}>
{p.name}
</option>
))}
</select>
<div
style={{
fontSize: "0.75rem",
display: "flex",
alignItems: "center",
flexWrap: "wrap",
gap: "0.25rem",
marginTop: "0.25rem",
}}
>
<input
type="checkbox"
checked={selectedSshKeyIdsForAction.includes(
key.id,
)}
onChange={(e) => {
if (e.target.checked) {
setSelectedSshKeyIdsForAction(
(prev) => [...prev, key.id],
);
} else {
setSelectedSshKeyIdsForAction(
(prev) =>
prev.filter(
(id) =>
id !== key.id,
),
);
}
}}
/>
{key.name}
</label>
))}
</div>
<button
className="primary-button small"
onClick={() =>
void handleRestart(
instance.id,
selectedProfileForAction || undefined,
selectedSshKeyIdsForAction.length > 0
? selectedSshKeyIdsForAction
: undefined,
)
}
type="button"
disabled={busyInstanceId === instance.id}
>
<Icon name="refresh" size="sm" />
Restart
</button>
<button
className="ghost-button small"
onClick={() => {
setProfileSelectInstanceId(null);
setSelectedProfileForAction("");
setSelectedSshKeyIdsForAction([]);
}}
type="button"
disabled={busyInstanceId === instance.id}
>
Cancel
</button>
</div>
) : (
<button
className="ghost-button small"
onClick={() => {
const toolType = toolTypes.find(
(t) => t.id === instance.tool_type_id,
);
if (toolType) {
void loadConfigProfiles(toolType.id);
}
setProfileSelectInstanceId(instance.id);
setSelectedProfileForAction(
instance.selected_config_profile_id || "",
);
setSelectedSshKeyIdsForAction(
instance.ssh_key_ids || [],
);
}}
type="button"
disabled={busyInstanceId === instance.id}
>
<Icon name="refresh" size="sm" />
</button>
)}
{sshKeys.map((key) => (
<label
key={key.id}
className="checkbox-label"
style={{
fontSize: "0.75rem",
display: "flex",
alignItems: "center",
gap: "0.25rem",
}}
>
<input
type="checkbox"
checked={selectedSshKeyIdsForAction.includes(
key.id,
)}
onChange={(e) => {
if (e.target.checked) {
setSelectedSshKeyIdsForAction((prev) => [
...prev,
key.id,
]);
} else {
setSelectedSshKeyIdsForAction((prev) =>
prev.filter((id) => id !== key.id),
);
}
}}
/>
{key.name}
</label>
))}
</div>
<button
className="primary-button small"
onClick={() =>
void handleRestart(
instance.id,
selectedProfileForAction || undefined,
selectedSshKeyIdsForAction.length > 0
? selectedSshKeyIdsForAction
: undefined,
)
}
type="button"
disabled={busyInstanceId === instance.id}
>
<Icon name="refresh" size="sm" />
Restart
</button>
<button
className="ghost-button small"
onClick={() => {
setProfileSelectInstanceId(null);
setSelectedProfileForAction("");
setSelectedSshKeyIdsForAction([]);
}}
type="button"
disabled={busyInstanceId === instance.id}
>
Cancel
</button>
</div>
) : (
<button
className="ghost-button small"
onClick={() => {
const toolType = toolTypes.find(
(t) => t.id === instance.tool_type_id,
);
if (toolType) {
void loadConfigProfiles(toolType.id);
}
setProfileSelectInstanceId(instance.id);
setSelectedProfileForAction(
instance.selected_config_profile_id || "",
);
setSelectedSshKeyIdsForAction(
instance.ssh_key_ids || [],
);
}}
type="button"
disabled={busyInstanceId === instance.id}
>
<Icon name="refresh" size="sm" />
</button>
)}
</>
)}
<button