feat: move terminal settings, look and ssh tools into ssh-terminal plugin

This commit is contained in:
LukeGus committed 2026-09-29 02:38:37 -05:00
1 parent ffa872ebd3
commit d9bba10612
242 files changed
+25071 -7207

No files matched your search

@@ -5,21 +5,18 @@ import {
CardContent,
ConnectionLogProvider,
ConnectionScreen,
DEFAULT_TERMINAL_CONFIG,
RobustClipboardProvider,
Select2,
TERMINAL_FONTS,
copyToClipboard,
ensureTerminalFontsLoaded,
isElectron,
pluginWsUrl,
readFromClipboard,
resolveConnectionOrigin,
resolveTermixThemeColors,
useAppTheme as useTheme,
useConnectionLog,
} from "@termix/plugin-sdk/ui";
import type { DockerHost } from "../types";
import { useConsoleLook, type ConsoleLook } from "./console-look";
import React from "react";
import { useXTerm } from "react-xtermjs";
import { FitAddon } from "@xterm/addon-fit";
@@ -32,6 +29,20 @@ import {
useConnectionRetry,
} from "@termix/plugin-sdk/frontend";
function applyConsoleLook(
terminal: NonNullable<ReturnType<typeof useXTerm>["instance"]>,
look: ConsoleLook,
): void {
terminal.options.cursorBlink = look.cursorBlink;
terminal.options.cursorStyle = look.cursorStyle;
terminal.options.fontSize = look.fontSize;
terminal.options.fontFamily = look.fontFamily;
terminal.options.scrollback = look.scrollback;
terminal.options.letterSpacing = look.letterSpacing;
terminal.options.lineHeight = look.lineHeight;
terminal.options.theme = { ...look.colors };
}
interface ConsoleTerminalProps {
containerId: string;
containerName: string;
@@ -60,20 +71,14 @@ function ConsoleTerminalInner({
const { instance: terminal, ref: xtermRef } = useXTerm();
const { addLog, clearLogs } = useConnectionLog();
const terminalConfig = React.useMemo(
() => ({
...DEFAULT_TERMINAL_CONFIG,
...(hostConfig.terminalConfig as Partial<
typeof DEFAULT_TERMINAL_CONFIG
> | null),
}),
[hostConfig.terminalConfig],
// The SSH terminal's look on this host, or plain colors while it is off.
const look = useConsoleLook(
hostConfig as unknown as Parameters<typeof useConsoleLook>[0],
appTheme,
);
const themeColors = React.useMemo(() => {
const activeTheme = terminalConfig.theme;
return resolveTermixThemeColors(activeTheme, appTheme);
}, [terminalConfig.theme, appTheme]);
const themeColors = look.colors;
const lookRef = React.useRef<ConsoleLook>(look);
lookRef.current = look;
const [isConnected, setIsConnected] = React.useState(false);
const [isConnecting, setIsConnecting] = React.useState(false);
@@ -96,19 +101,7 @@ function ConsoleTerminalInner({
terminal.loadAddon(clipboardAddon);
terminal.loadAddon(webLinksAddon);
const fontConfig = TERMINAL_FONTS.find(
(f) => f.value === terminalConfig.fontFamily,
);
const fontFamily = fontConfig?.fallback ?? TERMINAL_FONTS[0].fallback;
ensureTerminalFontsLoaded(fontConfig?.value ?? TERMINAL_FONTS[0].value);
terminal.options.cursorBlink = terminalConfig.cursorBlink;
terminal.options.cursorStyle = terminalConfig.cursorStyle;
terminal.options.fontSize = terminalConfig.fontSize;
terminal.options.fontFamily = fontFamily;
terminal.options.scrollback = terminalConfig.scrollback;
terminal.options.letterSpacing = terminalConfig.letterSpacing;
terminal.options.lineHeight = terminalConfig.lineHeight;
applyConsoleLook(terminal, lookRef.current);
const readTextFromClipboard = async (): Promise<string> => {
return readFromClipboard();
@@ -199,31 +192,6 @@ function ConsoleTerminalInner({
return true;
});
terminal.options.theme = {
background: themeColors.background,
foreground: themeColors.foreground,
cursor: themeColors.cursor,
cursorAccent: themeColors.cursorAccent,
selectionBackground: themeColors.selectionBackground,
selectionForeground: themeColors.selectionForeground,
black: themeColors.black,
red: themeColors.red,
green: themeColors.green,
yellow: themeColors.yellow,
blue: themeColors.blue,
magenta: themeColors.magenta,
cyan: themeColors.cyan,
white: themeColors.white,
brightBlack: themeColors.brightBlack,
brightRed: themeColors.brightRed,
brightGreen: themeColors.brightGreen,
brightYellow: themeColors.brightYellow,
brightBlue: themeColors.brightBlue,
brightMagenta: themeColors.brightMagenta,
brightCyan: themeColors.brightCyan,
brightWhite: themeColors.brightWhite,
};
setTimeout(() => {
fitAddon.fit();
}, 100);
@@ -262,7 +230,13 @@ function ConsoleTerminalInner({
terminal.dispose();
};
}, [terminal, t, terminalConfig, themeColors]);
}, [terminal, t]);
React.useEffect(() => {
if (!terminal) return;
applyConsoleLook(terminal, look);
fitAddonRef.current?.fit();
}, [terminal, look]);
const disconnect = React.useCallback(() => {
if (wsRef.current) {
@@ -0,0 +1,65 @@
import { useEffect, useState } from "react";
import {
invokeAction,
type PluginHostRecord,
} from "@termix/plugin-sdk/frontend";
/** What the SSH terminal's "terminal.resolveTheme" action answers. */
export interface ConsoleLook {
colors: Record<string, string | undefined> & {
background: string;
foreground: string;
};
fontFamily: string;
fontSize: number;
cursorStyle: "block" | "underline" | "bar";
cursorBlink: boolean;
letterSpacing: number;
lineHeight: number;
scrollback: number;
}
/** Plain colors, for when the SSH terminal plugin is off. */
export const FALLBACK_CONSOLE_LOOK: ConsoleLook = {
colors: {
background: "#0c0d0b",
foreground: "#fafafa",
cursor: "#fafafa",
cursorAccent: "#0c0d0b",
},
fontFamily: '"SF Mono", Consolas, "Liberation Mono", monospace',
fontSize: 14,
cursorStyle: "bar",
cursorBlink: true,
letterSpacing: 0,
lineHeight: 1,
scrollback: 10000,
};
/** The look the SSH terminal uses on this host, or plain colors without it. */
export function useConsoleLook(
host: PluginHostRecord | null | undefined,
appTheme: string,
): ConsoleLook {
const [look, setLook] = useState<ConsoleLook>(FALLBACK_CONSOLE_LOOK);
const hostKey = host
? `${host.id}:${JSON.stringify(host.pluginSettings ?? {})}`
: "";
useEffect(() => {
let active = true;
invokeAction("terminal.resolveTheme", { host, appTheme })
.then((resolved) => {
if (active) setLook((resolved as ConsoleLook) ?? FALLBACK_CONSOLE_LOOK);
})
.catch(() => {
if (active) setLook(FALLBACK_CONSOLE_LOOK);
});
return () => {
active = false;
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [hostKey, appTheme]);
return look;
}
-1
View File
@@ -56,7 +56,6 @@ export interface DockerHost {
username?: string;
syncId?: string | null;
connectionOrigin?: "local" | "remote" | null;
terminalConfig?: Record<string, unknown> | null;
pluginSettings?: Record<string, Record<string, unknown> | undefined>;
}
@@ -0,0 +1,16 @@
import { describe, expect, it } from "vitest";
import { renderHook, waitFor } from "@testing-library/react";
import {
FALLBACK_CONSOLE_LOOK,
useConsoleLook,
} from "../../../src/frontend/components/console-look";
describe("useConsoleLook", () => {
it("uses plain colors while the SSH terminal is off", async () => {
const { result } = renderHook(() =>
useConsoleLook({ id: "1", name: "h", ip: "10.0.0.1", port: 22 }, "dark"),
);
await waitFor(() => expect(result.current).toBe(FALLBACK_CONSOLE_LOOK));
expect(result.current.colors.background).toBe("#0c0d0b");
});
});