Nano zoom fix #11

This commit is contained in:
LukeGus
2024-12-05 19:19:04 -06:00
parent b6a3f881a8
commit 1a0d224ae0
10 changed files with 256 additions and 74 deletions

8
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

12
.idea/SSH-Project-JB.iml generated Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/SSH-Project-JB.iml" filepath="$PROJECT_DIR$/.idea/SSH-Project-JB.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@@ -24,7 +24,7 @@
}, },
"scripts": { "scripts": {
"start-vite": "cross-env BROWSER=none WDS_SOCKET_PORT=0 vite --port 8080", "start-vite": "cross-env BROWSER=none WDS_SOCKET_PORT=0 vite --port 8080",
"start-server": "node 'D:/Programming Projects/SSH-Project/ssh-project/backend/server.js'", "start-server": "node ./start.js",
"start": "npm run start-vite && npm run start-server", "start": "npm run start-vite && npm run start-server",
"build": "vite build", "build": "vite build",
"preview": "vite preview", "preview": "vite preview",

View File

@@ -63,7 +63,7 @@
.hide-sidebar-button { .hide-sidebar-button {
position: fixed; position: fixed;
bottom: 10px; bottom: 10px;
right: 10px; right: 25px;
background-color: rgb(108, 108, 108); background-color: rgb(108, 108, 108);
color: white; color: white;
border: none; border: none;

View File

@@ -16,85 +16,92 @@ const App = () => {
const [isSideBarHidden, setIsSideBarHidden] = useState(false); const [isSideBarHidden, setIsSideBarHidden] = useState(false);
useEffect(() => { useEffect(() => {
// Initialize the terminal and the fit addon console.log('Initializing terminal...');
terminal.current = new Terminal({ terminal.current = new Terminal({
cursorBlink: true, cursorBlink: true,
theme: { theme: { background: '#1e1e1e', foreground: '#ffffff' },
background: '#1e1e1e',
foreground: '#ffffff',
},
macOptionIsMeta: true, macOptionIsMeta: true,
allowProposedApi: true, allowProposedApi: true,
scrollback: 1000, // Allow scrollback so the terminal doesn't lose state fontSize: 14,
}); });
// Initialize and attach the fit addon to the terminal
fitAddon.current = new FitAddon(); fitAddon.current = new FitAddon();
terminal.current.loadAddon(fitAddon.current); terminal.current.loadAddon(fitAddon.current);
if (terminalRef.current) {
terminal.current.open(terminalRef.current); terminal.current.open(terminalRef.current);
console.log('Terminal opened successfully.');
} else {
console.error('Terminal reference is not valid!');
}
// Resize terminal to fit the container initially
fitAddon.current.fit();
// Adjust terminal size on window resize
const resizeListener = () => {
fitAddon.current.fit();
};
window.addEventListener('resize', resizeListener);
// Monitor terminal data (activity)
terminal.current.onData((data) => { terminal.current.onData((data) => {
if (socket.current && socket.current.readyState === WebSocket.OPEN) { if (socket.current && socket.current.readyState === WebSocket.OPEN) {
socket.current.send(data); socket.current.send(data);
} }
}); });
// Add specific resize call for certain programs like nano or vim const resizeTerminal = () => {
const resizeTerminalOnStart = () => { if (terminalRef.current) {
// Resize immediately after starting vim/nano or other programs
fitAddon.current.fit(); fitAddon.current.fit();
terminal.current.clear(); notifyServerOfResize();
}
}; };
terminal.current.onData((data) => { const notifyServerOfResize = () => {
if (data.includes('nano') || data.includes('vim')) { if (socket.current && socket.current.readyState === WebSocket.OPEN) {
// Trigger resize immediately when these programs start const { rows, cols } = terminal.current;
resizeTerminalOnStart(); socket.current.send(
JSON.stringify({
type: 'resize',
rows,
cols,
height: terminalRef.current.offsetHeight,
width: terminalRef.current.offsetWidth,
})
);
} }
}); };
resizeTerminal();
window.addEventListener('resize', resizeTerminal);
// Cleanup on component unmount
return () => { return () => {
terminal.current.dispose(); terminal.current.dispose();
if (socket.current) { if (socket.current) {
socket.current.close(); socket.current.close();
} }
window.removeEventListener('resize', resizeListener); window.removeEventListener('resize', resizeTerminal);
}; };
}, []); }, []);
const handleConnect = () => { const handleConnect = () => {
console.log('Connecting...');
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = `${protocol}//${window.location.host}/ws/`; // Use current host and "/ws/" endpoint const wsUrl = `${protocol}//${window.location.host}/ws/`;
console.log(`WebSocket URL: ${wsUrl}`);
socket.current = new WebSocket(wsUrl); socket.current = new WebSocket(wsUrl);
socket.current.onopen = () => { socket.current.onopen = () => {
console.log('WebSocket connection opened');
terminal.current.writeln(`Connected to WebSocket server at ${wsUrl}`); terminal.current.writeln(`Connected to WebSocket server at ${wsUrl}`);
socket.current.send(JSON.stringify({ host, username, password })); socket.current.send(JSON.stringify({ host, username, password }));
setIsConnected(true); setIsConnected(true);
}; };
socket.current.onmessage = (event) => { socket.current.onmessage = (event) => {
console.log('Received message:', event.data);
terminal.current.write(event.data); terminal.current.write(event.data);
}; };
socket.current.onerror = (error) => { socket.current.onerror = (error) => {
console.error('WebSocket error:', error);
terminal.current.writeln(`WebSocket error: ${error.message}`); terminal.current.writeln(`WebSocket error: ${error.message}`);
}; };
socket.current.onclose = () => { socket.current.onclose = () => {
console.log('WebSocket connection closed');
terminal.current.writeln('Disconnected from WebSocket server.'); terminal.current.writeln('Disconnected from WebSocket server.');
setIsConnected(false); setIsConnected(false);
}; };
@@ -106,6 +113,12 @@ const App = () => {
const handleSideBarHiding = () => { const handleSideBarHiding = () => {
setIsSideBarHidden((prevState) => !prevState); setIsSideBarHidden((prevState) => !prevState);
if (!isSideBarHidden) {
setTimeout(() => {
fitAddon.current.fit();
notifyServerOfResize();
}, 100);
}
}; };
return ( return (
@@ -139,11 +152,7 @@ const App = () => {
<div ref={terminalRef} className="terminal-container"></div> <div ref={terminalRef} className="terminal-container"></div>
</div> </div>
{/* Hide button always positioned in the bottom-right corner */} <button className="hide-sidebar-button" onClick={handleSideBarHiding}>
<button
className="hide-sidebar-button"
onClick={handleSideBarHiding}
>
{isSideBarHidden ? '+' : '-'} {isSideBarHidden ? '+' : '-'}
</button> </button>
</div> </div>

12
frontend/start.js Normal file
View File

@@ -0,0 +1,12 @@
// start.js
const { spawn } = require('child_process');
const child = spawn('node', ["\"D:/Programming Projects/SSH-Project-JB/backend/server.js\""], {
stdio: 'inherit', // this is key for interactivity
shell: true, // use system shell
});
child.on('exit', function (code, signal) {
console.log('child process exited with ' +
`code ${code} and signal ${signal}`);
});

128
package-lock.json generated
View File

@@ -1,13 +1,90 @@
{ {
"name": "ssh-project", "name": "SSH-Project-JB",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"dependencies": { "dependencies": {
"cross-env": "^7.0.3",
"xterm-addon-fit": "^0.8.0" "xterm-addon-fit": "^0.8.0"
} }
}, },
"node_modules/cross-env": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
"dependencies": {
"cross-spawn": "^7.0.1"
},
"bin": {
"cross-env": "src/bin/cross-env.js",
"cross-env-shell": "src/bin/cross-env-shell.js"
},
"engines": {
"node": ">=10.14",
"npm": ">=6",
"yarn": ">=1"
}
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
},
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"engines": {
"node": ">=8"
}
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dependencies": {
"shebang-regex": "^3.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"engines": {
"node": ">=8"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dependencies": {
"isexe": "^2.0.0"
},
"bin": {
"node-which": "bin/node-which"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/xterm": { "node_modules/xterm": {
"version": "5.3.0", "version": "5.3.0",
"license": "MIT", "license": "MIT",
@@ -24,6 +101,55 @@
} }
}, },
"dependencies": { "dependencies": {
"cross-env": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
"requires": {
"cross-spawn": "^7.0.1"
}
},
"cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"requires": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
}
},
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
},
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
},
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"requires": {
"shebang-regex": "^3.0.0"
}
},
"shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"requires": {
"isexe": "^2.0.0"
}
},
"xterm": { "xterm": {
"version": "5.3.0", "version": "5.3.0",
"peer": true "peer": true

View File

@@ -1,5 +1,6 @@
{ {
"dependencies": { "dependencies": {
"cross-env": "^7.0.3",
"xterm-addon-fit": "^0.8.0" "xterm-addon-fit": "^0.8.0"
} }
} }