Release 1.0 (#3)
* Nano and timeout error fix #1 * Nano and timeout error fix #2 * Nano and timeout error fix #3 * Nano and timeout error fix #4 * Nano and timeout error fix #5 * Nano and timeout error fix #6 * Nano and timeout error fix #7 (plus css changes for hide buttons) * Nano and timeout error fix #8 (zoom method) * Nano zoom fix #9 * Nano zoom fix #10 * Nano zoom fix #11 * Nano zoom fix #12 * Nano zoom fix #13 * Nano zoom fix #14 * Nano zoom fix #15 * Nano zoom fix #16 (ssh-2-promise) * Nano zoom fix #17 (ssh-2-promise port fix) * Full return back to old code with minor fixes * Terminal size fix #18 (rows & cols fix) * Test ntfy build notification system * Silent resize cmds & Auto resize terminal #1 * Silent resize cmds & Auto resize terminal #2 * Docker build update * Docker build update #2 * Docker build update #3 * Docker build update #4 (cache and cleanup) * Docker build update #5 (cache and cleanup) * Docker build update #6 (cache and cleanup) * Docker build update #7 (final) * Docker build update #8 (nevermind not finanl) * Docker build update #9 (nevermind not finanl) * Docker build update #10 * Docker build update #10 (I hope final) * Docker build update #10 (actual final) * Release 1.0!!!! * Repo clean-up * Remove files ignored by .gitignore * Change project name, create logo, change README.md to be soon updated. * Update README.md #1 (also added MIT License) * Update README.md #2 * Update README.md #3 * Update README.md #4 * Update README.md #5 * Update README.md #6 * Update README.md #7 * Update README.md * Add images * Update image name * Update README.md * Final changes to release-1.0 * Update README.md * Update name (need to fix logo) * Final updates (I hope for real this time) * Fix web-socket timeout. * Fix timeout on close.
This commit was merged in pull request #3.
This commit is contained in:
@@ -22,7 +22,6 @@
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -63,7 +62,7 @@
|
||||
.hide-sidebar-button {
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
right: 23px;
|
||||
background-color: rgb(108, 108, 108);
|
||||
color: white;
|
||||
border: none;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { Terminal } from 'xterm';
|
||||
import { Terminal } from '@xterm/xterm';
|
||||
import 'xterm/css/xterm.css';
|
||||
import { FitAddon } from 'xterm-addon-fit';
|
||||
import { FitAddon } from '@xterm/addon-fit';
|
||||
import './App.css';
|
||||
|
||||
const App = () => {
|
||||
@@ -10,13 +10,13 @@ const App = () => {
|
||||
const fitAddon = useRef(null);
|
||||
const socket = useRef(null);
|
||||
const [host, setHost] = useState('');
|
||||
const [port, setPort] = useState('22');
|
||||
const [username, setUsername] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
const [isSideBarHidden, setIsSideBarHidden] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// Initialize the terminal and the fit addon
|
||||
terminal.current = new Terminal({
|
||||
cursorBlink: true,
|
||||
theme: {
|
||||
@@ -25,23 +25,37 @@ const App = () => {
|
||||
},
|
||||
macOptionIsMeta: true,
|
||||
allowProposedApi: true,
|
||||
scrollback: 1000, // Allow scrollback so the terminal doesn't lose state
|
||||
scrollback: 5000,
|
||||
});
|
||||
|
||||
// Initialize and attach the fit addon to the terminal
|
||||
fitAddon.current = new FitAddon();
|
||||
terminal.current.loadAddon(fitAddon.current);
|
||||
|
||||
terminal.current.open(terminalRef.current);
|
||||
|
||||
// Resize terminal to fit the container initially
|
||||
fitAddon.current.fit();
|
||||
|
||||
// Adjust terminal size on window resize
|
||||
const resizeListener = () => {
|
||||
// Fit the terminal and send the size when needed
|
||||
const fitAndNotifyResize = () => {
|
||||
fitAddon.current.fit();
|
||||
if (socket.current && socket.current.readyState === WebSocket.OPEN) {
|
||||
socket.current.send(JSON.stringify({
|
||||
cols: terminal.current.cols,
|
||||
rows: terminal.current.rows,
|
||||
}));
|
||||
}
|
||||
};
|
||||
window.addEventListener('resize', resizeListener);
|
||||
window.addEventListener('resize', fitAndNotifyResize);
|
||||
|
||||
terminal.current.onResize(({ cols, rows }) => {
|
||||
console.log(`Terminal resized to cols:${cols}, rows:${rows}`);
|
||||
fitAndNotifyResize();
|
||||
});
|
||||
|
||||
const handleConnectionEstablished = () => {
|
||||
fitAndNotifyResize();
|
||||
};
|
||||
|
||||
window.addEventListener('connection-established', handleConnectionEstablished);
|
||||
|
||||
// Monitor terminal data (activity)
|
||||
terminal.current.onData((data) => {
|
||||
@@ -50,50 +64,54 @@ const App = () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Add specific resize call for certain programs like nano or vim
|
||||
const resizeTerminalOnStart = () => {
|
||||
// Resize immediately after starting vim/nano or other programs
|
||||
fitAddon.current.fit();
|
||||
terminal.current.clear();
|
||||
};
|
||||
|
||||
terminal.current.onData((data) => {
|
||||
if (data.includes('nano') || data.includes('vim')) {
|
||||
// Trigger resize immediately when these programs start
|
||||
resizeTerminalOnStart();
|
||||
}
|
||||
});
|
||||
|
||||
// Cleanup on component unmount
|
||||
return () => {
|
||||
terminal.current.dispose();
|
||||
if (socket.current) {
|
||||
socket.current.close();
|
||||
}
|
||||
window.removeEventListener('resize', resizeListener);
|
||||
window.removeEventListener('resize', fitAndNotifyResize);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleConnect = () => {
|
||||
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
const wsUrl = `${protocol}//${window.location.host}/ws/`; // Use current host and "/ws/" endpoint
|
||||
|
||||
socket.current = new WebSocket(wsUrl);
|
||||
|
||||
|
||||
if (!host || !username || !password) {
|
||||
terminal.current.writeln('Please fill in all fields.');
|
||||
return;
|
||||
}
|
||||
|
||||
socket.current = new WebSocket("ws://localhost:8081");
|
||||
|
||||
socket.current.onopen = () => {
|
||||
terminal.current.writeln(`Connected to WebSocket server at ${wsUrl}`);
|
||||
socket.current.send(JSON.stringify({ host, username, password }));
|
||||
socket.current.send(
|
||||
JSON.stringify({
|
||||
host,
|
||||
port,
|
||||
username,
|
||||
password,
|
||||
rows: terminal.current.rows,
|
||||
cols: terminal.current.cols
|
||||
})
|
||||
);
|
||||
|
||||
// Dispatch a custom event when connection is open
|
||||
const event = new Event('connection-established');
|
||||
window.dispatchEvent(event);
|
||||
|
||||
setIsConnected(true);
|
||||
};
|
||||
|
||||
|
||||
socket.current.onmessage = (event) => {
|
||||
terminal.current.write(event.data);
|
||||
};
|
||||
|
||||
|
||||
socket.current.onerror = (error) => {
|
||||
terminal.current.writeln(`WebSocket error: ${error.message}`);
|
||||
};
|
||||
|
||||
|
||||
socket.current.onclose = () => {
|
||||
terminal.current.writeln('Disconnected from WebSocket server.');
|
||||
setIsConnected(false);
|
||||
@@ -105,48 +123,80 @@ const App = () => {
|
||||
};
|
||||
|
||||
const handleSideBarHiding = () => {
|
||||
setIsSideBarHidden((prevState) => !prevState);
|
||||
setIsSideBarHidden((prevState) => {
|
||||
const newState = !prevState;
|
||||
if (newState) {
|
||||
setTimeout(() => {
|
||||
// Add a delay to ensure layout settles before resize action
|
||||
fitAddon.current.fit();
|
||||
if (socket.current && socket.current.readyState === WebSocket.OPEN) {
|
||||
socket.current.send(JSON.stringify({
|
||||
cols: terminal.current.cols,
|
||||
rows: terminal.current.rows,
|
||||
}));
|
||||
}
|
||||
}, 100); // Delay of 100 milliseconds
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
// Refit terminal when showing sidebar as well
|
||||
fitAddon.current.fit();
|
||||
if (socket.current && socket.current.readyState === WebSocket.OPEN) {
|
||||
socket.current.send(JSON.stringify({
|
||||
cols: terminal.current.cols,
|
||||
rows: terminal.current.rows,
|
||||
}));
|
||||
}
|
||||
}, 100); // Delay of 100 milliseconds
|
||||
}
|
||||
return newState;
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="app-container">
|
||||
<div className="main-content">
|
||||
<div className={`sidebar ${isSideBarHidden ? 'hidden' : ''}`}>
|
||||
<h2>Connection Details</h2>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Host"
|
||||
value={host}
|
||||
onChange={(e) => handleInputChange(e, setHost)}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
value={username}
|
||||
onChange={(e) => handleInputChange(e, setUsername)}
|
||||
/>
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
value={password}
|
||||
onChange={(e) => handleInputChange(e, setPassword)}
|
||||
/>
|
||||
<button onClick={handleConnect} disabled={isConnected}>
|
||||
{isConnected ? 'Connected' : 'Start Session'}
|
||||
</button>
|
||||
<div className="app-container">
|
||||
<div className="main-content">
|
||||
<div className={`sidebar ${isSideBarHidden ? 'hidden' : ''}`}>
|
||||
<h2>Connection Details</h2>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Host"
|
||||
value={host}
|
||||
onChange={(e) => handleInputChange(e, setHost)}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Port"
|
||||
value={port}
|
||||
onChange={(e) => handleInputChange(e, setPort)}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
value={username}
|
||||
onChange={(e) => handleInputChange(e, setUsername)}
|
||||
/>
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
value={password}
|
||||
onChange={(e) => handleInputChange(e, setPassword)}
|
||||
/>
|
||||
<button onClick={handleConnect} disabled={isConnected}>
|
||||
{isConnected ? 'Connected' : 'Start Session'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div ref={terminalRef} className="terminal-container"></div>
|
||||
</div>
|
||||
|
||||
<div ref={terminalRef} className="terminal-container"></div>
|
||||
{/* Hide button always positioned in the bottom-right corner */}
|
||||
<button
|
||||
className="hide-sidebar-button"
|
||||
onClick={handleSideBarHiding}
|
||||
>
|
||||
{isSideBarHidden ? '+' : '-'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Hide button always positioned in the bottom-right corner */}
|
||||
<button
|
||||
className="hide-sidebar-button"
|
||||
onClick={handleSideBarHiding}
|
||||
>
|
||||
{isSideBarHidden ? '+' : '-'}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ body {
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
overflow: hidden; /* Prevent scrolling */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
code {
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 49 KiB |
Reference in New Issue
Block a user