mirror of
https://github.com/tale/headplane.git
synced 2026-07-27 16:18:57 +00:00
fix: resize cols and rows, not the other way around *sigh*
This commit is contained in:
@@ -23,6 +23,13 @@ export async function loader({
|
||||
request,
|
||||
context,
|
||||
}: LoaderFunctionArgs<LoadContext>) {
|
||||
if (!context.agents?.agentID()) {
|
||||
throw data(
|
||||
'WebSSH is only available with the Headplane agent integration',
|
||||
400,
|
||||
);
|
||||
}
|
||||
|
||||
const session = await context.sessions.auth(request);
|
||||
const user = session.get('user');
|
||||
if (!user) {
|
||||
@@ -35,6 +42,7 @@ export async function loader({
|
||||
'v1/user',
|
||||
session.get('api_key')!,
|
||||
);
|
||||
|
||||
// MARK: This assumes that a user has authenticated with Headscale first
|
||||
// Since the only way to enforce permissions via ACLs is to generate a
|
||||
// pre-authkey which REQUIRES a user ID, meaning the user has to have
|
||||
|
||||
Vendored
-12
@@ -46,18 +46,6 @@ interface XtermConfig {
|
||||
OnDisconnect: () => void;
|
||||
}
|
||||
|
||||
// interface SSHTerminalConfig {
|
||||
// writeFn: (data: string) => void;
|
||||
// writeErrorFn: (error: string) => void;
|
||||
// setReadFn: (cb: (input: string) => void) => void;
|
||||
// rows: number;
|
||||
// cols: number;
|
||||
// timeoutSeconds?: number;
|
||||
// onConnectionProgress: (message: string) => void;
|
||||
// onConnected: () => void;
|
||||
// onDone: () => void;
|
||||
// }
|
||||
|
||||
interface SSHSession {
|
||||
Close(): boolean;
|
||||
Resize(rows: number, cols: number): boolean;
|
||||
|
||||
@@ -30,6 +30,17 @@ export default function XTerm({ ipn, username, hostname }: XTermProps) {
|
||||
|
||||
useEffect(() => {
|
||||
pause();
|
||||
if (!container.current) {
|
||||
console.error('Container ref is not set');
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't create a new terminal if one already exists
|
||||
if (term.current) {
|
||||
console.warn('Terminal already exists, skipping initialization');
|
||||
return;
|
||||
}
|
||||
|
||||
const terminal = new xterm.Terminal({
|
||||
allowProposedApi: true,
|
||||
cursorBlink: true,
|
||||
@@ -52,24 +63,23 @@ export default function XTerm({ ipn, username, hostname }: XTermProps) {
|
||||
);
|
||||
|
||||
terminal.unicode.activeVersion = '11';
|
||||
const gl = new WebglAddon();
|
||||
terminal.loadAddon(gl);
|
||||
|
||||
const fit = new FitAddon();
|
||||
terminal.loadAddon(fit);
|
||||
|
||||
const gl = new WebglAddon();
|
||||
terminal.loadAddon(gl);
|
||||
|
||||
gl.onContextLoss(() => {
|
||||
console.warn('WebGL context lost, falling back to canvas rendering');
|
||||
gl.dispose();
|
||||
});
|
||||
|
||||
fit.fit();
|
||||
term.current = terminal;
|
||||
terminal.open(container.current!);
|
||||
terminal.focus();
|
||||
term.current = terminal;
|
||||
|
||||
let ro: ResizeObserver | null = null;
|
||||
let onUnload: ((e: Event) => void) | null = null;
|
||||
|
||||
const session = ipn.OpenSSH(hostname, username, {
|
||||
Rows: terminal.rows,
|
||||
Cols: terminal.cols,
|
||||
@@ -103,8 +113,7 @@ export default function XTerm({ ipn, username, hostname }: XTermProps) {
|
||||
},
|
||||
});
|
||||
|
||||
const parent = container.current?.ownerDocument.defaultView ?? window;
|
||||
ro = new parent.ResizeObserver(() => {
|
||||
const ro = new ResizeObserver(() => {
|
||||
if (term.current) {
|
||||
setIsResizing(true);
|
||||
fit.fit();
|
||||
@@ -112,12 +121,10 @@ export default function XTerm({ ipn, username, hostname }: XTermProps) {
|
||||
}
|
||||
});
|
||||
|
||||
if (container.current) {
|
||||
ro.observe(container.current);
|
||||
}
|
||||
|
||||
ro.observe(container.current);
|
||||
terminal.onResize(({ cols, rows }) => {
|
||||
session.Resize(rows, cols);
|
||||
console.log(`Terminal resized to ${cols}x${rows}`);
|
||||
session.Resize(cols, rows);
|
||||
});
|
||||
|
||||
terminal.onData((data) => {
|
||||
@@ -126,12 +133,25 @@ export default function XTerm({ ipn, username, hostname }: XTermProps) {
|
||||
|
||||
onUnload = (_) => session.Close();
|
||||
parent.addEventListener('unload', onUnload);
|
||||
|
||||
return () => {
|
||||
if (onUnload) {
|
||||
parent.removeEventListener('unload', onUnload);
|
||||
}
|
||||
|
||||
session.Close();
|
||||
ro?.disconnect();
|
||||
terminal.dispose();
|
||||
term.current = null;
|
||||
inputRef.current = null;
|
||||
console.log('SSH session closed and terminal disposed');
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="relative w-full h-full group">
|
||||
<>
|
||||
{isLoading ? (
|
||||
<div className="mx-auto h-screen flex items-center justify-center">
|
||||
<div className="absolute w-screen z-50 mx-auto h-screen flex items-center justify-center">
|
||||
<Loader2 className="animate-spin size-10 text-headplane-50" />
|
||||
</div>
|
||||
) : undefined}
|
||||
@@ -159,6 +179,6 @@ export default function XTerm({ ipn, username, hostname }: XTermProps) {
|
||||
Failed to connect to SSH session
|
||||
</div>
|
||||
) : undefined}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ func (s *SSHSession) Resize(rows, cols int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.Pty.WindowChange(rows, cols)
|
||||
return s.Pty.WindowChange(cols, rows)
|
||||
}
|
||||
|
||||
// Closes the SSH session.
|
||||
|
||||
Reference in New Issue
Block a user