Merge remote-tracking branch 'origin/dev-1.10.1' into dev-1.10.1

This commit is contained in:
LukeGus
2026-01-12 23:58:52 -06:00
3 changed files with 49 additions and 16 deletions

View File

@@ -211,7 +211,7 @@ class UserDataImport {
newHostData,
targetUserId,
options.userDataKey,
);
) as Record<string, unknown>;
}
delete processedHostData.id;
@@ -294,7 +294,7 @@ class UserDataImport {
newCredentialData,
targetUserId,
options.userDataKey,
);
) as Record<string, unknown>;
}
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 { NetworkGraphView } from "@/ui/desktop/dashboard/network-graph";
import { Toaster } from "@/components/ui/sonner.tsx";
import { toast } from "sonner";
import { CommandPalette } from "@/ui/desktop/apps/command-palette/CommandPalette.tsx";
import { getUserInfo, logoutUser, isElectron } from "@/ui/main-axios.ts";
import { useTheme } from "@/components/theme-provider";
@@ -89,30 +90,44 @@ function AppContent() {
useEffect(() => {
const path = window.location.pathname;
const match = path.match(/^\/hosts\/([a-zA-Z0-9_-]+)\/terminal$/);
if (match) {
const hostId = match[1];
const openTerminalForHost = async () => {
// New format: /terminal/{hostNameOrId}
const terminalMatch = path.match(/^\/terminal\/([a-zA-Z0-9_-]+)$/);
// Legacy format: /hosts/{id}/terminal (backward compatible)
const legacyMatch = path.match(/^\/hosts\/([a-zA-Z0-9_-]+)\/terminal$/);
const hostIdentifier = terminalMatch?.[1] || legacyMatch?.[1];
if (hostIdentifier) {
const openTerminal = async () => {
try {
const { getSSHHostById } = await import("@/ui/main-axios.ts");
const host = await getSSHHostById(parseInt(hostId, 10));
const { getSSHHostById, getSSHHosts } = await import("@/ui/main-axios.ts");
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) {
addTab({
type: "terminal",
title: host.name || host.ip,
data: {
host,
initialCommand: "",
},
data: { host, initialCommand: "" },
});
// Clean URL to prevent re-opening on refresh
window.history.replaceState({}, "", "/");
} else {
toast.error(`Host "${hostIdentifier}" not found`);
}
} 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");
}
};
openTerminalForHost();
openTerminal();
}
}, [addTab]);

View File

@@ -1349,6 +1349,24 @@ export const Terminal = forwardRef<TerminalHandle, SSHTerminalProps>(
return true;
}
// Ctrl+Alt+<key> → Ctrl+<key> remapping for browser-blocked shortcuts
// Browsers intercept Ctrl+W/T/N/Q, so we use Ctrl+Alt as an alternative
if (e.ctrlKey && e.altKey && !e.metaKey && !e.shiftKey) {
const key = e.key.toLowerCase();
const blockedKeys = ["w", "t", "n", "q"];
if (blockedKeys.includes(key)) {
e.preventDefault();
e.stopPropagation();
const ctrlCode = key.charCodeAt(0) - 96;
if (webSocketRef.current?.readyState === 1) {
webSocketRef.current.send(
JSON.stringify({ type: "input", data: String.fromCharCode(ctrlCode) }),
);
}
return false;
}
}
if (showAutocompleteRef.current) {
if (e.key === "Escape") {
e.preventDefault();