fix(terminal): keep SSH reconnect banner above the xterm canvas (#10242)
Portal the non-blocking reconnect banner into each pane container so WebGL compositing cannot paint terminal text through it, raise z-index above pane-local chrome, and use a fully opaque card background.
This commit is contained in:
parent
34e0233cf5
commit
f26ea6a4a5
|
|
@ -2896,16 +2896,23 @@ export default function TerminalPane({
|
|||
onRestartDaemon={() => daemonActions.setPending('restart')}
|
||||
/>
|
||||
)}
|
||||
{showSshReconnectOverlay && sshReconnectTargetId && sshReconnectStatus ? (
|
||||
<TerminalSshReconnectOverlay
|
||||
targetId={sshReconnectTargetId}
|
||||
targetLabel={sshReconnectTargetLabel}
|
||||
status={sshReconnectStatus}
|
||||
targetRemoved={sshReconnectTargetRemoved}
|
||||
worktreeId={worktreeId}
|
||||
sshOwnerEnvironmentId={sshReconnectEnvironmentId}
|
||||
/>
|
||||
) : null}
|
||||
{/* Why: portal into the pane so the banner stacks above the xterm canvas (sibling mount painted under WebGL). */}
|
||||
{showSshReconnectOverlay && sshReconnectTargetId && sshReconnectStatus
|
||||
? managedPanes.map((pane) =>
|
||||
createPortal(
|
||||
<TerminalSshReconnectOverlay
|
||||
targetId={sshReconnectTargetId}
|
||||
targetLabel={sshReconnectTargetLabel}
|
||||
status={sshReconnectStatus}
|
||||
targetRemoved={sshReconnectTargetRemoved}
|
||||
worktreeId={worktreeId}
|
||||
sshOwnerEnvironmentId={sshReconnectEnvironmentId}
|
||||
/>,
|
||||
pane.container,
|
||||
`ssh-reconnect-${pane.id}`
|
||||
)
|
||||
)
|
||||
: null}
|
||||
<DaemonActionDialog api={daemonActions} />
|
||||
{isActive && (
|
||||
<TerminalSessionStateSaveFailureDialog
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ describe('TerminalSshReconnectOverlay', () => {
|
|||
expect(screen.getByText(/This terminal is waiting for devbox/)).toBeInTheDocument()
|
||||
expect(screen.getByRole('status')).toBeInTheDocument()
|
||||
const banner = container.querySelector('[data-terminal-ssh-reconnect-banner="disconnected"]')
|
||||
expect(banner).toHaveClass('inset-x-3', 'bottom-3')
|
||||
expect(banner).toHaveClass('inset-x-3', 'bottom-3', 'z-40')
|
||||
expect(banner).not.toHaveClass('inset-0', 'bg-background/75')
|
||||
await user.click(screen.getByRole('button', { name: 'Connect' }))
|
||||
|
||||
|
|
|
|||
|
|
@ -136,13 +136,14 @@ export function TerminalSshReconnectOverlay({
|
|||
}
|
||||
}, [isConnecting, mountedRef, setSshConnectionState, sshOwnerEnvironmentId, targetId])
|
||||
|
||||
// Why: z-40 clears pane-local chrome (focus rim z-30); bg-card is fully opaque so terminal text cannot paint through.
|
||||
return (
|
||||
<div
|
||||
className="pointer-events-none absolute inset-x-3 bottom-3 z-30 flex justify-center"
|
||||
className="pointer-events-none absolute inset-x-3 bottom-3 z-40 flex justify-center"
|
||||
data-terminal-ssh-reconnect-banner={status}
|
||||
>
|
||||
<div
|
||||
className="pointer-events-auto flex w-full max-w-xl items-center gap-3 rounded-md border border-border bg-card/95 px-3 py-3 text-card-foreground shadow-xs backdrop-blur-[1px]"
|
||||
className="pointer-events-auto flex w-full max-w-xl items-center gap-3 rounded-md border border-border bg-card px-3 py-3 text-card-foreground shadow-xs"
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
>
|
||||
|
|
|
|||
Loading…
Reference in New Issue