feat: support URL routes to open terminal directly (#156) #503

Merged
ZacharyZcR merged 3 commits from feat/url-terminal-route into dev-1.10.1 2026-01-13 05:57:10 +00:00
2 changed files with 31 additions and 16 deletions

View File

@@ -211,7 +211,7 @@ class UserDataImport {
newHostData, newHostData,
targetUserId, targetUserId,
options.userDataKey, options.userDataKey,
); ) as Record<string, unknown>;
} }
delete processedHostData.id; delete processedHostData.id;
@@ -294,7 +294,7 @@ class UserDataImport {
newCredentialData, newCredentialData,
targetUserId, targetUserId,
options.userDataKey, options.userDataKey,
); ) as Record<string, unknown>;
} }
delete processedCredentialData.id; delete processedCredentialData.id;

View File

@@ -13,6 +13,7 @@ import { AdminSettings } from "@/ui/desktop/apps/admin/AdminSettings.tsx";
import { UserProfile } from "@/ui/desktop/user/UserProfile.tsx"; import { UserProfile } from "@/ui/desktop/user/UserProfile.tsx";
import { NetworkGraphView } from "@/ui/desktop/dashboard/network-graph"; import { NetworkGraphView } from "@/ui/desktop/dashboard/network-graph";
import { Toaster } from "@/components/ui/sonner.tsx"; import { Toaster } from "@/components/ui/sonner.tsx";
import { toast } from "sonner";
import { CommandPalette } from "@/ui/desktop/apps/command-palette/CommandPalette.tsx"; import { CommandPalette } from "@/ui/desktop/apps/command-palette/CommandPalette.tsx";
import { getUserInfo, logoutUser, isElectron } from "@/ui/main-axios.ts"; import { getUserInfo, logoutUser, isElectron } from "@/ui/main-axios.ts";
import { useTheme } from "@/components/theme-provider"; import { useTheme } from "@/components/theme-provider";
@@ -89,30 +90,44 @@ function AppContent() {
useEffect(() => { useEffect(() => {
const path = window.location.pathname; const path = window.location.pathname;
const match = path.match(/^\/hosts\/([a-zA-Z0-9_-]+)\/terminal$/); // New format: /terminal/{hostNameOrId}
if (match) { const terminalMatch = path.match(/^\/terminal\/([a-zA-Z0-9_-]+)$/);
const hostId = match[1]; // Legacy format: /hosts/{id}/terminal (backward compatible)
const legacyMatch = path.match(/^\/hosts\/([a-zA-Z0-9_-]+)\/terminal$/);
const hostIdentifier = terminalMatch?.[1] || legacyMatch?.[1];
const openTerminalForHost = async () => { if (hostIdentifier) {
const openTerminal = async () => {
try { try {
const { getSSHHostById } = await import("@/ui/main-axios.ts"); const { getSSHHostById, getSSHHosts } = await import("@/ui/main-axios.ts");
const host = await getSSHHostById(parseInt(hostId, 10)); let host = null;
// Pure numeric → lookup by ID
if (/^\d+$/.test(hostIdentifier)) {
host = await getSSHHostById(parseInt(hostIdentifier, 10));
} else {
// Non-numeric → lookup by name (first match)
const hosts = await getSSHHosts();
host = hosts.find((h: { name?: string }) => h.name === hostIdentifier) || null;
}
if (host) { if (host) {
addTab({ addTab({
type: "terminal", type: "terminal",
title: host.name || host.ip, title: host.name || host.ip,
data: { data: { host, initialCommand: "" },
host,
initialCommand: "",
},
}); });
// Clean URL to prevent re-opening on refresh
window.history.replaceState({}, "", "/");
} else {
toast.error(`Host "${hostIdentifier}" not found`);
} }
} catch (error) { } catch (error) {
console.error("Failed to open terminal for host:", error); console.error("Failed to open terminal:", error);
toast.error("Failed to open terminal for host");
} }
}; };
openTerminal();
openTerminalForHost();
} }
}, [addTab]); }, [addTab]);