feat: convert ssh tunnels into a plugin

This commit is contained in:
LukeGus committed 2026-09-23 17:27:28 -05:00
1 parent c85c1fdb86
commit 1682861853
220 files changed
+36928 -11374

No files matched your search

-2
View File
@@ -19,7 +19,6 @@ import {
MessagesSquare,
LifeBuoy,
Search,
Network,
User,
KeyRound,
Layers, // --- tmux-monitor ---
@@ -73,7 +72,6 @@ function getSshActions(host: Host): {
icon: Layers,
label: "Tmux Monitor",
},
host.enableTunnel && { type: "tunnel", icon: Network, label: "Tunnels" },
].filter(Boolean) as {
type: TabType;
icon: React.ElementType;
+2 -8
View File
@@ -111,11 +111,7 @@ export function TabProvider({ children }: TabProviderProps) {
const computeUniqueTitle = useCallback(
(tabType: Tab["type"], desiredTitle: string | undefined): string => {
const defaultTitle =
tabType === "file_manager"
? t("nav.fileManager")
: tabType === "tunnel"
? t("nav.tunnels")
: t("nav.terminal");
tabType === "file_manager" ? t("nav.fileManager") : t("nav.terminal");
const baseTitle = (desiredTitle || defaultTitle).trim();
const match = baseTitle.match(/^(.*) \((\d+)\)$/);
const root = match ? match[1] : baseTitle;
@@ -180,9 +176,7 @@ export function TabProvider({ children }: TabProviderProps) {
const id = nextTabId.current++;
const instanceId = `tab_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
const needsUniqueTitle =
tabData.type === "terminal" ||
tabData.type === "file_manager" ||
tabData.type === "tunnel";
tabData.type === "terminal" || tabData.type === "file_manager";
const effectiveTitle = needsUniqueTitle
? computeUniqueTitle(tabData.type, tabData.title)
: tabData.type === "tmux_monitor" // --- tmux-monitor ---
-2
View File
@@ -19,7 +19,6 @@ import { getTabType } from "./tab-registry";
* not a meaningful part of an arrangement.
*/
const CORE_CAPTURABLE = new Set([
"tunnel",
"tmux_monitor",
"serial",
"homepage",
@@ -32,7 +31,6 @@ const CORE_CAPTURABLE = new Set([
/** Core types reopened as singletons, with an optional preselected host. */
const CORE_SINGLETON = new Set([
"tunnel",
"tmux_monitor",
"homepage",
"termix-id",
+2 -2
View File
@@ -83,11 +83,11 @@ export const useTabTypes = registry.useList;
export const resetTabTypes = registry.reset;
/** Core tab types that are saved and reopened after login. */
const CORE_PERSISTENT = new Set(["tunnel"]);
const CORE_PERSISTENT = new Set<string>();
/** Core tab types that hold a live session (close confirm, refresh). */
const CORE_SESSION = new Set(["serial"]);
/** Core tab types that restore without a host. */
const CORE_HOSTLESS = new Set(["dashboard", "tunnel"]);
const CORE_HOSTLESS = new Set(["dashboard"]);
/**
* A plugin tab type nobody registered right now: its plugin is off, failed or
+1 -15
View File
@@ -4,7 +4,6 @@ import {
LayoutDashboard,
LayoutGrid,
LayoutPanelLeft,
Network,
Server,
Settings,
Usb,
@@ -59,11 +58,6 @@ const HomepageCanvas = lazy(() =>
default: m.HomepageCanvas,
})),
);
const loadTunnelTab = () =>
import("@/features/tunnel/TunnelTab").then((m) => ({
default: m.TunnelTab,
}));
const TunnelTab = lazy(loadTunnelTab);
const Serial = lazy(() =>
import("@/features/serial/Serial").then((m) => ({
default: m.Serial,
@@ -89,7 +83,6 @@ const SshToolsPanel = lazy(() =>
);
const tabSurfaceLoaders: Partial<Record<TabType, () => Promise<unknown>>> = {
tmux_monitor: loadTmuxMonitor,
tunnel: loadTunnelTab,
};
/** Download a likely next tab without starting a connection or mounting UI. */
@@ -161,8 +154,6 @@ export function tabIcon(type: TabType) {
return <User className="size-3.5" />;
case "admin-settings":
return <Settings className="size-3.5" />;
case "tunnel":
return <Network className="size-3.5" />;
// --- tmux-monitor ---
case "tmux_monitor":
return <Layers className="size-3.5" />;
@@ -259,7 +250,7 @@ export interface TabRenderContext {
export function renderTabContent(tab: Tab, context: TabRenderContext) {
const { shell, isVisible = true, isFocusedPane = true, panelProps } = context;
const { host, label } = tab;
const { host } = tab;
switch (tab.type) {
case "dashboard":
@@ -276,11 +267,6 @@ export function renderTabContent(tab: Tab, context: TabRenderContext) {
<LocalTerminal instanceId={tab.instanceId} isVisible={isVisible} />,
);
case "tunnel":
return withTabSuspense(
<TunnelTab label={label} host={host} isVisible={isVisible} />,
);
// --- tmux-monitor ---
case "tmux_monitor":
return withTabSuspense(