feat(terminal): styling improvements and shortcut
This commit is contained in:
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 = '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
Reference in New Issue
Block a user