mirror of
https://github.com/tailscale/tailscale.git
synced 2025-03-23 01:31:06 +00:00
cmd/tsconnect: temporarily switch to xterm.js fork that handles popup windows
Allows other work to be unblocked while xtermjs/xterm.js#4069 is worked through. To enable testing the popup window handling, the standalone app allows opening of SSH sessions in new windows by holding down the alt key while pressing the SSH button. Signed-off-by: Mihai Parparita <mihai@tailscale.com>
This commit is contained in:
parent
2400ba28b1
commit
01e6565e8a
@ -10,7 +10,7 @@
|
||||
"qrcode": "^1.5.0",
|
||||
"tailwindcss": "^3.1.6",
|
||||
"typescript": "^4.7.4",
|
||||
"xterm": "^4.18.0",
|
||||
"xterm": "mihaip/xterm.js#95100e3c870b59348bb4fa5504bab9f9317bac67",
|
||||
"xterm-addon-fit": "^0.5.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
@ -2,16 +2,24 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
import { useState, useCallback } from "preact/hooks"
|
||||
import { useState, useCallback, useMemo, useEffect, useRef } from "preact/hooks"
|
||||
import { createPortal } from "preact/compat"
|
||||
import type { VNode } from "preact"
|
||||
import { runSSHSession, SSHSessionDef } from "../lib/ssh"
|
||||
|
||||
export function SSH({ netMap, ipn }: { netMap: IPNNetMap; ipn: IPN }) {
|
||||
const [sshSessionDef, setSSHSessionDef] = useState<SSHSessionDef | null>(null)
|
||||
const [sshSessionDef, setSSHSessionDef] = useState<SSHFormSessionDef | null>(
|
||||
null
|
||||
)
|
||||
const clearSSHSessionDef = useCallback(() => setSSHSessionDef(null), [])
|
||||
if (sshSessionDef) {
|
||||
return (
|
||||
const sshSession = (
|
||||
<SSHSession def={sshSessionDef} ipn={ipn} onDone={clearSSHSessionDef} />
|
||||
)
|
||||
if (sshSessionDef.newWindow) {
|
||||
return <NewWindow close={clearSSHSessionDef}>{sshSession}</NewWindow>
|
||||
}
|
||||
return sshSession
|
||||
}
|
||||
const sshPeers = netMap.peers.filter(
|
||||
(p) => p.tailscaleSSHEnabled && p.online !== false
|
||||
@ -24,6 +32,8 @@ export function SSH({ netMap, ipn }: { netMap: IPNNetMap; ipn: IPN }) {
|
||||
return <SSHForm sshPeers={sshPeers} onSubmit={setSSHSessionDef} />
|
||||
}
|
||||
|
||||
type SSHFormSessionDef = SSHSessionDef & { newWindow?: boolean }
|
||||
|
||||
function SSHSession({
|
||||
def,
|
||||
ipn,
|
||||
@ -33,20 +43,14 @@ function SSHSession({
|
||||
ipn: IPN
|
||||
onDone: () => void
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
class="flex-grow bg-black p-2 overflow-hidden"
|
||||
ref={(node) => {
|
||||
if (node) {
|
||||
// Run the SSH session aysnchronously, so that the React render
|
||||
// loop is complete (otherwise the SSH form may still be visible,
|
||||
// which affects the size of the terminal, leading to a spurious
|
||||
// initial resize).
|
||||
setTimeout(() => runSSHSession(node, def, ipn, onDone), 0)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
useEffect(() => {
|
||||
if (ref.current) {
|
||||
runSSHSession(ref.current, def, ipn, onDone)
|
||||
}
|
||||
}, [ref])
|
||||
|
||||
return <div class="flex-grow bg-black p-2 overflow-hidden" ref={ref} />
|
||||
}
|
||||
|
||||
function NoSSHPeers() {
|
||||
@ -66,7 +70,7 @@ function SSHForm({
|
||||
onSubmit,
|
||||
}: {
|
||||
sshPeers: IPNNetMapPeerNode[]
|
||||
onSubmit: (def: SSHSessionDef) => void
|
||||
onSubmit: (def: SSHFormSessionDef) => void
|
||||
}) {
|
||||
sshPeers = sshPeers.slice().sort((a, b) => a.name.localeCompare(b.name))
|
||||
const [username, setUsername] = useState("")
|
||||
@ -99,7 +103,51 @@ function SSHForm({
|
||||
type="submit"
|
||||
class="button bg-green-500 border-green-500 text-white hover:bg-green-600 hover:border-green-600"
|
||||
value="SSH"
|
||||
onClick={(e) => {
|
||||
if (e.altKey) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
onSubmit({ username, hostname, newWindow: true })
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
const NewWindow = ({
|
||||
children,
|
||||
close,
|
||||
}: {
|
||||
children: VNode
|
||||
close: () => void
|
||||
}) => {
|
||||
const newWindow = useMemo(() => {
|
||||
const newWindow = window.open(undefined, undefined, "width=600,height=400")
|
||||
if (newWindow) {
|
||||
const containerNode = newWindow.document.createElement("div")
|
||||
containerNode.className = "h-screen flex flex-col overflow-hidden"
|
||||
newWindow.document.body.appendChild(containerNode)
|
||||
|
||||
for (const linkNode of document.querySelectorAll(
|
||||
"head link[rel=stylesheet]"
|
||||
)) {
|
||||
const newLink = document.createElement("link")
|
||||
newLink.rel = "stylesheet"
|
||||
newLink.href = (linkNode as HTMLLinkElement).href
|
||||
newWindow.document.head.appendChild(newLink)
|
||||
}
|
||||
}
|
||||
return newWindow
|
||||
}, [])
|
||||
if (!newWindow) {
|
||||
console.error("Could not open window")
|
||||
return null
|
||||
}
|
||||
newWindow.onbeforeunload = () => {
|
||||
close()
|
||||
}
|
||||
|
||||
useEffect(() => () => newWindow.close(), [])
|
||||
return createPortal(children, newWindow.document.body.lastChild as Element)
|
||||
}
|
||||
|
@ -54,7 +54,10 @@ export function runSSHSession(
|
||||
})
|
||||
|
||||
// Make terminal and SSH session track the size of the containing DOM node.
|
||||
resizeObserver = new ResizeObserver(() => fitAddon.fit())
|
||||
resizeObserver =
|
||||
new termContainerNode.ownerDocument.defaultView!.ResizeObserver(() =>
|
||||
fitAddon.fit()
|
||||
)
|
||||
resizeObserver.observe(termContainerNode)
|
||||
term.onResize(({ rows, cols }) => sshSession.resize(rows, cols))
|
||||
|
||||
|
@ -644,10 +644,9 @@ xterm-addon-fit@^0.5.0:
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-fit/-/xterm-addon-fit-0.5.0.tgz#2d51b983b786a97dcd6cde805e700c7f913bc596"
|
||||
integrity sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ==
|
||||
|
||||
xterm@^4.18.0:
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.18.0.tgz#a1f6ab2c330c3918fb094ae5f4c2562987398ea1"
|
||||
integrity sha512-JQoc1S0dti6SQfI0bK1AZvGnAxH4MVw45ZPFSO6FHTInAiau3Ix77fSxNx3mX4eh9OL4AYa8+4C8f5UvnSfppQ==
|
||||
xterm@mihaip/xterm.js#95100e3c870b59348bb4fa5504bab9f9317bac67:
|
||||
version "4.19.0"
|
||||
resolved "https://codeload.github.com/mihaip/xterm.js/tar.gz/95100e3c870b59348bb4fa5504bab9f9317bac67"
|
||||
|
||||
y18n@^4.0.0:
|
||||
version "4.0.3"
|
||||
|
Loading…
x
Reference in New Issue
Block a user