Advertisement
Guest User

Untitled

a guest
Dec 6th, 2024
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import React, { useEffect, useRef, useState } from 'react';
  2. import { Terminal } from 'xterm';
  3. import 'xterm/css/xterm.css';
  4. import { FitAddon } from 'xterm-addon-fit';
  5. import './App.css';
  6.  
  7. const App = () => {
  8.   const terminalRef = useRef(null);
  9.   const terminal = useRef(null);
  10.   const fitAddon = useRef(null);
  11.   const socket = useRef(null);
  12.   const [host, setHost] = useState('');
  13.   const [username, setUsername] = useState('');
  14.   const [password, setPassword] = useState('');
  15.   const [isConnected, setIsConnected] = useState(false);
  16.   const [isSideBarHidden, setIsSideBarHidden] = useState(false);
  17.  
  18.   useEffect(() => {
  19.     // Initialize the terminal and the fit addon
  20.     terminal.current = new Terminal({
  21.       cursorBlink: true,
  22.       theme: {
  23.         background: '#1e1e1e',
  24.         foreground: '#ffffff',
  25.       },
  26.       macOptionIsMeta: true,
  27.       allowProposedApi: true,
  28.       scrollback: 5000,
  29.     });
  30.  
  31.     // Initialize and attach the fit addon to the terminal
  32.     fitAddon.current = new FitAddon();
  33.     terminal.current.loadAddon(fitAddon.current);
  34.  
  35.     terminal.current.open(terminalRef.current);
  36.  
  37.     // Resize terminal to fit the container initially
  38.     fitAddon.current.fit();
  39.  
  40.     // Adjust terminal size on window resize
  41.     const resizeListener = () => {
  42.       fitAddon.current.fit();
  43.     };
  44.     window.addEventListener('resize', resizeListener);
  45.  
  46.     // Monitor terminal data (activity)
  47.     terminal.current.onData((data) => {
  48.       if (socket.current && socket.current.readyState === WebSocket.OPEN) {
  49.         socket.current.send(data);
  50.       }
  51.     });
  52.  
  53.     // Add specific resize call for certain programs like nano or vim
  54.     const resizeTerminalOnStart = () => {
  55.       // Resize immediately after starting vim/nano or other programs
  56.       fitAddon.current.fit();
  57.       terminal.current.clear();
  58.     };
  59.  
  60.     terminal.current.onData((data) => {
  61.       if (data.includes('nano') || data.includes('vim')) {
  62.         // Trigger resize immediately when these programs start
  63.         resizeTerminalOnStart();
  64.       }
  65.     });
  66.  
  67.     // Cleanup on component unmount
  68.     return () => {
  69.       terminal.current.dispose();
  70.       if (socket.current) {
  71.         socket.current.close();
  72.       }
  73.       window.removeEventListener('resize', resizeListener);
  74.     };
  75.   }, []);
  76.  
  77.   const handleConnect = () => {
  78.     const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
  79.     const wsUrl = `${protocol}//${window.location.host}/ws/`; // Use current host and "/ws/" endpoint
  80.  
  81.     if (!host || !username || !password) {
  82.       terminal.current.writeln('Please fill in all fields.');
  83.       return;
  84.     }
  85.  
  86.     socket.current = new WebSocket(wsUrl);
  87.  
  88.     socket.current.onopen = () => {
  89.       terminal.current.writeln(`Connected to WebSocket server at ${wsUrl}`);
  90.       socket.current.send(JSON.stringify({ host, username, password }));
  91.       setIsConnected(true);
  92.     };
  93.  
  94.     socket.current.onmessage = (event) => {
  95.       terminal.current.write(event.data);
  96.     };
  97.  
  98.     socket.current.onerror = (error) => {
  99.       terminal.current.writeln(`WebSocket error: ${error.message}`);
  100.     };
  101.  
  102.     socket.current.onclose = () => {
  103.       terminal.current.writeln('Disconnected from WebSocket server.');
  104.       setIsConnected(false);
  105.     };
  106.   };
  107.  
  108.   const handleInputChange = (event, setState) => {
  109.     setState(event.target.value);
  110.   };
  111.  
  112.   const handleSideBarHiding = () => {
  113.     setIsSideBarHidden((prevState) => !prevState);
  114.   };
  115.  
  116.   return (
  117.       <div className="app-container">
  118.         <div className="main-content">
  119.           <div className={`sidebar ${isSideBarHidden ? 'hidden' : ''}`}>
  120.             <h2>Connection Details</h2>
  121.             <input
  122.                 type="text"
  123.                 placeholder="Host"
  124.                 value={host}
  125.                 onChange={(e) => handleInputChange(e, setHost)}
  126.             />
  127.             <input
  128.                 type="text"
  129.                 placeholder="Username"
  130.                 value={username}
  131.                 onChange={(e) => handleInputChange(e, setUsername)}
  132.             />
  133.             <input
  134.                 type="password"
  135.                 placeholder="Password"
  136.                 value={password}
  137.                 onChange={(e) => handleInputChange(e, setPassword)}
  138.             />
  139.             <button onClick={handleConnect} disabled={isConnected}>
  140.               {isConnected ? 'Connected' : 'Start Session'}
  141.             </button>
  142.           </div>
  143.  
  144.           <div ref={terminalRef} className="terminal-container"></div>
  145.         </div>
  146.  
  147.         {/* Hide button always positioned in the bottom-right corner */}
  148.         <button
  149.             className="hide-sidebar-button"
  150.             onClick={handleSideBarHiding}
  151.         >
  152.           {isSideBarHidden ? '+' : '-'}
  153.         </button>
  154.       </div>
  155.   );
  156. };
  157.  
  158. export default App;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement