This commit is contained in:
EthanShoeDev
2025-09-19 23:41:17 -04:00
parent f0321c48e7
commit e1d8dc76c9
7 changed files with 39 additions and 23 deletions

View File

@@ -151,14 +151,14 @@ function ShellDetail() {
style={{ flex: 1 }}
logger={{
log: console.log,
debug: console.log,
// debug: console.log,
warn: console.warn,
error: console.error,
}}
// xterm options
xtermOptions={{
theme: {
background: 'red',
background: theme.colors.background,
foreground: theme.colors.textPrimary,
},
}}

View File

@@ -19,15 +19,15 @@ export const useSshConnMutation = (opts?: {
const security =
connectionDetails.security.type === 'password'
? {
type: 'password' as const,
password: connectionDetails.security.password,
}
type: 'password' as const,
password: connectionDetails.security.password,
}
: {
type: 'key' as const,
privateKey: await secretsManager.keys.utils
.getPrivateKey(connectionDetails.security.keyId)
.then((e) => e.value),
};
type: 'key' as const,
privateKey: await secretsManager.keys.utils
.getPrivateKey(connectionDetails.security.keyId)
.then((e) => e.value),
};
const sshConnection = await connect({
host: connectionDetails.host,

View File

@@ -82,9 +82,9 @@ function makeBetterSecureStore<
const unsafedRootManifest: unknown = rawRootManifestString
? JSON.parse(rawRootManifestString)
: {
manifestVersion: rootManifestVersion,
manifestChunksIds: [],
};
manifestVersion: rootManifestVersion,
manifestChunksIds: [],
};
const rootManifest = rootManifestSchema.parse(unsafedRootManifest);
const manifestChunks = await Promise.all(
rootManifest.manifestChunksIds.map(async (manifestChunkId) => {
@@ -409,7 +409,11 @@ async function upsertConnection(params: {
priority: number;
label?: string;
}) {
const id = `${params.details.username}-${params.details.host}-${params.details.port}`.replaceAll('.', '_');
const id =
`${params.details.username}-${params.details.host}-${params.details.port}`.replaceAll(
'.',
'_',
);
await betterConnectionStorage.upsertEntry({
id,
metadata: {

View File

@@ -94,7 +94,7 @@ if (window.__FRESSH_XTERM_BRIDGE__) {
break;
}
case 'setOptions': {
const newOpts: ITerminalOptions = {
const newOpts: ITerminalOptions & { cols?: never; rows?: never } = {
...term.options,
...msg.opts,
theme: {
@@ -102,6 +102,8 @@ if (window.__FRESSH_XTERM_BRIDGE__) {
...msg.opts.theme,
},
};
delete newOpts.cols;
delete newOpts.rows;
term.options = newOpts;
if (
'theme' in newOpts &&
@@ -109,7 +111,7 @@ if (window.__FRESSH_XTERM_BRIDGE__) {
'background' in newOpts.theme &&
newOpts.theme.background
) {
document.body.style.backgroundColor = 'blue'; // TODO: Just for debugging
document.body.style.backgroundColor = newOpts.theme.background;
}
break;
}

View File

@@ -1,5 +1,6 @@
import { Base64 } from 'js-base64';
type ITerminalOptions = import('@xterm/xterm').ITerminalOptions;
type ITerminalInitOnlyOptions = import('@xterm/xterm').ITerminalInitOnlyOptions;
// Messages posted from the WebView (xterm page) to React Native
export type BridgeInboundMessage =
| { type: 'initialized' }
@@ -12,7 +13,11 @@ export type BridgeOutboundMessage =
| { type: 'writeMany'; chunks: string[] }
| { type: 'resize'; cols: number; rows: number }
| { type: 'fit' }
| { type: 'setOptions'; opts: Partial<ITerminalOptions> }
| {
type: 'setOptions'; opts: Partial<
Omit<ITerminalOptions, keyof ITerminalInitOnlyOptions>
>
}
| { type: 'clear' }
| { type: 'focus' };

View File

@@ -4,6 +4,7 @@ import React, {
useMemo,
useRef,
useCallback,
useState,
} from 'react';
import { WebView, type WebViewMessageEvent } from 'react-native-webview';
import htmlString from '../dist-internal/index.html?raw';
@@ -63,7 +64,7 @@ const defaultWebViewProps: WebViewOptions = {
const defaultXtermOptions: Partial<ITerminalOptions> = {
fontFamily: 'Menlo, ui-monospace, monospace',
fontSize: 80,
fontSize: 20,
cursorBlink: true,
scrollback: 10000,
};
@@ -125,6 +126,7 @@ export function XtermJsWebView({
autoFit = true,
}: XtermJsWebViewProps) {
const webRef = useRef<WebView>(null);
const [initialized, setInitialized] = useState(false);
// ---- RN -> WebView message sender
const sendToWebView = useCallback(
@@ -132,7 +134,7 @@ export function XtermJsWebView({
const webViewRef = webRef.current;
if (!webViewRef) return;
const payload = JSON.stringify(obj);
logger?.log?.(`sending msg to webview: ${payload}`);
logger?.debug?.(`sending msg to webview: ${payload}`);
const js = `window.dispatchEvent(new MessageEvent('message',{data:${payload}})); true;`;
webViewRef.injectJavaScript(js);
},
@@ -211,6 +213,7 @@ export function XtermJsWebView({
const appliedSizeRef = useRef<{ cols: number; rows: number } | null>(null);
useEffect(() => {
if (!initialized) return;
const appliedSize = appliedSizeRef.current;
if (!size) return;
if (appliedSize?.cols === size.cols && appliedSize?.rows === size.rows)
@@ -221,7 +224,7 @@ export function XtermJsWebView({
autoFitFn();
appliedSizeRef.current = size;
}, [size, sendToWebView, logger, autoFitFn]);
}, [size, sendToWebView, logger, autoFitFn, initialized]);
useImperativeHandle(ref, () => ({
write,
@@ -251,13 +254,14 @@ export function XtermJsWebView({
const appliedXtermOptionsRef = useRef<Partial<ITerminalOptions> | null>(null);
useEffect(() => {
if (!initialized) return;
const appliedXtermOptions = appliedXtermOptionsRef.current;
if (xTermOptionsEquals(appliedXtermOptions, mergedXTermOptions)) return;
logger?.log?.(`setting options: `, mergedXTermOptions);
sendToWebView({ type: 'setOptions', opts: mergedXTermOptions });
appliedXtermOptionsRef.current = mergedXTermOptions;
}, [mergedXTermOptions, sendToWebView, logger]);
}, [mergedXTermOptions, sendToWebView, logger, initialized]);
const onMessage = useCallback(
(e: WebViewMessageEvent) => {
@@ -267,6 +271,7 @@ export function XtermJsWebView({
if (msg.type === 'initialized') {
onInitialized?.();
autoFitFn();
setInitialized(true);
return;
}
if (msg.type === 'input') {

View File

@@ -8,12 +8,12 @@
// Special tasks
"build:main": {
"inputs": ["src/**"],
"inputs": ["src/**", "vite.config.ts"],
"dependsOn": ["build:internal"],
"outputs": ["dist/**"],
},
"build:internal": {
"inputs": ["src-internal/**"],
"inputs": ["src-internal/**", "index.html", "vite.config.internal.ts"],
"outputs": ["dist-internal/**"],
},
},