feat(terminal): styling improvements and shortcut

This commit is contained in:
2025-10-02 20:26:34 +02:00
parent 7cee2ff94f
commit 489fdafa1c
4 changed files with 108 additions and 11 deletions

View File

@@ -517,11 +517,11 @@ class ClusterMembersComponent extends Component {
}); });
} }
if (terminalBtn) { if (terminalBtn) {
this.addEventListener(terminalBtn, 'click', async (e) => { this.addEventListener(terminalBtn, 'click', async (e) => {
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
try { try {
if (!window.TerminalPanel) return; if (!window.TerminalPanel) return;
this.ensureTerminalContainer(); this.ensureTerminalContainer();
const panel = window.TerminalPanel; const panel = window.TerminalPanel;
@@ -530,11 +530,11 @@ class ClusterMembersComponent extends Component {
if (wasMinimized && panel.restore) { if (wasMinimized && panel.restore) {
panel.restore(); panel.restore();
} }
} catch (err) { } catch (err) {
console.error('Failed to open member terminal:', err); console.error('Failed to open member terminal:', err);
} }
}); });
} }
}); });
}, 100); }, 100);
} }

View File

@@ -75,6 +75,9 @@ class DrawerComponent {
const panel = window.TerminalPanel; const panel = window.TerminalPanel;
const wasMinimized = panel.isMinimized; const wasMinimized = panel.isMinimized;
panel.open(this.terminalPanelContainer, nodeIp); panel.open(this.terminalPanelContainer, nodeIp);
if (nodeIp && panel._updateTitle) {
panel._updateTitle(nodeIp);
}
if (wasMinimized && panel.restore) { if (wasMinimized && panel.restore) {
panel.restore(); panel.restore();
} }

View File

@@ -14,6 +14,14 @@
this.dockEl = null; this.dockEl = null;
this.dockBtnEl = null; this.dockBtnEl = null;
this.lastNodeIp = null; this.lastNodeIp = null;
this.fallbackContainer = null;
try {
this._onKeydown = this._onKeydown.bind(this);
document.addEventListener('keydown', this._onKeydown);
} catch (_) {
// ignore if document not available
}
} }
open(container, nodeIp) { open(container, nodeIp) {
@@ -60,6 +68,8 @@
this._connect(nodeIp); this._connect(nodeIp);
} else if (this.lastNodeIp && !this.socket) { } else if (this.lastNodeIp && !this.socket) {
this._connect(this.lastNodeIp); this._connect(this.lastNodeIp);
} else if (!this.socket && !this.lastNodeIp) {
this._updateTitle(null);
} }
} catch (err) { } catch (err) {
console.error('TerminalPanel.open error:', err); console.error('TerminalPanel.open error:', err);
@@ -136,8 +146,7 @@
_connect(nodeIp) { _connect(nodeIp) {
try { try {
const titleEl = this.panelEl.querySelector('.terminal-title'); this._updateTitle(nodeIp);
if (titleEl) titleEl.textContent = `Terminal — ${nodeIp}`;
// Close previous socket if switching node // Close previous socket if switching node
if (this.socket) { if (this.socket) {
@@ -254,6 +263,75 @@
if (this.dockEl) this.dockEl.classList.remove('visible'); if (this.dockEl) this.dockEl.classList.remove('visible');
} }
_resolveContainer() {
if (this.container && document.body && document.body.contains(this.container)) {
return this.container;
}
const sharedDrawer = window.__sharedDrawerInstance;
if (sharedDrawer && sharedDrawer.terminalPanelContainer) {
return sharedDrawer.terminalPanelContainer;
}
if (this.fallbackContainer && document.body && document.body.contains(this.fallbackContainer)) {
return this.fallbackContainer;
}
if (typeof document !== 'undefined') {
const fallback = document.createElement('div');
fallback.className = 'terminal-panel-container';
document.body.appendChild(fallback);
this.fallbackContainer = fallback;
return fallback;
}
return null;
}
_onKeydown(event) {
try {
if (!event || event.defaultPrevented) return;
if (event.key !== 't' && event.key !== 'T') return;
if (event.repeat) return;
if (event.metaKey || event.ctrlKey || event.altKey) return;
const activeEl = document.activeElement;
if (activeEl) {
const tagName = activeEl.tagName;
const isEditable = activeEl.isContentEditable;
if (isEditable || tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT') {
return;
}
}
event.preventDefault();
this.toggleVisibility();
} catch (_) {
// swallow errors from key handler to avoid breaking global listeners
}
}
toggleVisibility() {
try {
if (this.isOpen && !this.isMinimized) {
this.minimize();
return;
}
if (this.isOpen && this.isMinimized) {
this.restore();
return;
}
const targetContainer = this._resolveContainer();
if (!targetContainer) return;
const targetIp = this.lastNodeIp || this.connectedIp || null;
this.open(targetContainer, targetIp);
} catch (err) {
console.error('TerminalPanel.toggleVisibility error:', err);
}
}
_send(text) { _send(text) {
try { try {
if (!this.socket || this.socket.readyState !== 1) { if (!this.socket || this.socket.readyState !== 1) {
@@ -267,6 +345,13 @@
} }
} }
_updateTitle(nodeIp) {
if (!this.panelEl) return;
const titleEl = this.panelEl.querySelector('.terminal-title');
if (!titleEl) return;
titleEl.textContent = nodeIp ? `Terminal — ${nodeIp}` : 'Terminal';
}
_clear() { _clear() {
if (this.logEl) this.logEl.textContent = ''; if (this.logEl) this.logEl.textContent = '';
} }

View File

@@ -59,6 +59,15 @@ class TopologyGraphComponent extends Component {
`; `;
}); });
}); });
try {
if (window.TerminalPanel && typeof nodeData.ip === 'string') {
window.TerminalPanel.lastNodeIp = nodeData.ip;
if (window.TerminalPanel._updateTitle) {
window.TerminalPanel._updateTitle(nodeData.ip);
}
}
} catch (_) {}
} }
closeDrawer() { closeDrawer() {