mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-27 06:34:06 +00:00
Fix: Terminal Resize (#6448)
* fix: added watcher on parent div resize and window resize and calls fit() on both events * removed effects and moved the resize handling to ref callback * fix: added ResizeObserver cleanup * fix: improve terminal resizing logic - Refactored fit logic to avoid unnecessary calls during hidden states. - Enhanced error handling when creating new terminal sessions. - Updated ResizeObserver to ensure proper fitting on container resize. * fix: remove unused fitRafRef in TerminalTab component * fix: refactor terminal mount logic to use a dedicated callback --------- Co-authored-by: Sid <siddharth@usebruno.com>
This commit is contained in:
committed by
GitHub
parent
7164119695
commit
3552e7e609
@@ -183,6 +183,29 @@ const openTerminalIntoContainer = async (container, sessionId) => {
|
||||
}
|
||||
};
|
||||
|
||||
let fitFrameRef;
|
||||
const fitTerminal = (activeSessionId, container) => {
|
||||
if (!container) return;
|
||||
|
||||
const instance = terminalInstances.get(activeSessionId);
|
||||
if (!instance?.fitAddon) return;
|
||||
|
||||
if (fitFrameRef) {
|
||||
cancelAnimationFrame(fitFrameRef);
|
||||
}
|
||||
|
||||
fitFrameRef = requestAnimationFrame(() => {
|
||||
fitFrameRef = null;
|
||||
|
||||
// Avoid fitting when hidden/0-sized (common during tab switches/layout transitions)
|
||||
if (container.offsetWidth === 0 || container.offsetHeight === 0) return;
|
||||
|
||||
try {
|
||||
instance.fitAddon.fit();
|
||||
} catch (e) {}
|
||||
});
|
||||
};
|
||||
|
||||
const TerminalTab = () => {
|
||||
const terminalRef = useRef(null);
|
||||
const [sessions, setSessions] = useState([]);
|
||||
@@ -223,22 +246,25 @@ const TerminalTab = () => {
|
||||
}, []);
|
||||
|
||||
// Create new terminal session
|
||||
const createNewSession = useCallback(async (cwd = null) => {
|
||||
if (!window.ipcRenderer) return null;
|
||||
const createNewSession = useCallback(
|
||||
async (cwd = null) => {
|
||||
if (!window.ipcRenderer) return null;
|
||||
|
||||
try {
|
||||
const options = cwd ? { cwd } : {};
|
||||
const newSessionId = await window.ipcRenderer.invoke('terminal:create', options);
|
||||
if (newSessionId) {
|
||||
await loadSessions(newSessionId);
|
||||
setActiveSessionId(newSessionId);
|
||||
return newSessionId;
|
||||
try {
|
||||
const options = cwd ? { cwd } : {};
|
||||
const newSessionId = await window.ipcRenderer.invoke('terminal:create', options);
|
||||
if (newSessionId) {
|
||||
await loadSessions(newSessionId);
|
||||
setActiveSessionId(newSessionId);
|
||||
return newSessionId;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Failed to create terminal session:', err);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Failed to create terminal session:', err);
|
||||
}
|
||||
return null;
|
||||
}, [loadSessions]);
|
||||
return null;
|
||||
},
|
||||
[loadSessions]
|
||||
);
|
||||
|
||||
// Listen for requests to open terminal at specific CWD
|
||||
useEffect(() => {
|
||||
@@ -339,31 +365,17 @@ const TerminalTab = () => {
|
||||
|
||||
if (mounted) {
|
||||
const instance = terminalInstances.get(activeSessionId);
|
||||
if (instance && instance.fitAddon) {
|
||||
const onResize = () => {
|
||||
try {
|
||||
instance.fitAddon.fit();
|
||||
} catch (e) {}
|
||||
};
|
||||
|
||||
window.addEventListener('resize', onResize);
|
||||
|
||||
// Initial resize
|
||||
setTimeout(() => {
|
||||
try {
|
||||
instance.fitAddon.fit();
|
||||
const { cols, rows } = instance.terminal;
|
||||
if (cols && rows && window.ipcRenderer) {
|
||||
window.ipcRenderer.send('terminal:resize', activeSessionId, { cols, rows });
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Failed to perform initial resize:', err);
|
||||
if (instance) {
|
||||
try {
|
||||
const { cols, rows } = instance.terminal;
|
||||
if (cols && rows && window.ipcRenderer) {
|
||||
window.ipcRenderer.send('terminal:resize', activeSessionId, { cols, rows });
|
||||
}
|
||||
}, 100);
|
||||
} catch (err) {
|
||||
console.warn('Failed to perform initial resize:', err);
|
||||
}
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('resize', onResize);
|
||||
|
||||
// Park terminal element when switching sessions
|
||||
if (instance.terminal && instance.terminal.element) {
|
||||
const host = ensureParkingHost();
|
||||
@@ -386,6 +398,18 @@ const TerminalTab = () => {
|
||||
};
|
||||
}, [activeSessionId]);
|
||||
|
||||
const onSessionMount = useCallback(
|
||||
(node) => {
|
||||
if (!node) return;
|
||||
terminalRef.current = node;
|
||||
fitTerminal(activeSessionId, node);
|
||||
const ro = new ResizeObserver(() => fitTerminal(activeSessionId, node));
|
||||
ro.observe(node.parentNode);
|
||||
return () => ro.disconnect();
|
||||
},
|
||||
[activeSessionId]
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<div className="terminal-content">
|
||||
@@ -405,13 +429,9 @@ const TerminalTab = () => {
|
||||
</div>
|
||||
<div className="terminal-sessions-list">
|
||||
{isLoading ? (
|
||||
<div style={{ padding: '12px', color: '#888', fontSize: '13px' }}>
|
||||
Loading sessions...
|
||||
</div>
|
||||
<div style={{ padding: '12px', color: '#888', fontSize: '13px' }}>Loading sessions...</div>
|
||||
) : sessions.length === 0 ? (
|
||||
<div style={{ padding: '12px', color: '#888', fontSize: '13px' }}>
|
||||
No active sessions
|
||||
</div>
|
||||
<div style={{ padding: '12px', color: '#888', fontSize: '13px' }}>No active sessions</div>
|
||||
) : (
|
||||
<SessionList
|
||||
sessions={sessions}
|
||||
@@ -432,7 +452,7 @@ const TerminalTab = () => {
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
ref={terminalRef}
|
||||
ref={onSessionMount}
|
||||
className="terminal-container"
|
||||
style={{
|
||||
height: '100%',
|
||||
|
||||
Reference in New Issue
Block a user