test
This commit is contained in:
parent
bcfb9eb5f5
commit
814b892551
@ -1,6 +1,6 @@
|
|||||||
import { Box, Paper, ThemeProvider, List, ListItem, ListItemButton, ListItemText, SwipeableDrawer, ListItemIcon, IconButton, AppBar, Toolbar, PaletteMode, createTheme, useMediaQuery, useTheme } from "@mui/material";
|
import { Box, Paper, ThemeProvider, List, ListItem, ListItemButton, ListItemText, SwipeableDrawer, ListItemIcon, IconButton, AppBar, Toolbar, PaletteMode, createTheme, useMediaQuery, useTheme } from "@mui/material";
|
||||||
import React, { Dispatch, ReactNode } from "react";
|
import React, { Dispatch, ReactNode } from "react";
|
||||||
import { BrowserRouter, Routes, Route, Navigate, useSearchParams } from "react-router-dom";
|
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
|
||||||
import { ApiWrapper, getDesignTokens, GlobalUserInfo } from "./common";
|
import { ApiWrapper, getDesignTokens, GlobalUserInfo } from "./common";
|
||||||
import { LoginPage } from "./login";
|
import { LoginPage } from "./login";
|
||||||
import ServersBoard from "./servers";
|
import ServersBoard from "./servers";
|
||||||
@ -14,7 +14,6 @@ import { SignupPage } from "./signup";
|
|||||||
import Brightness4Icon from '@mui/icons-material/Brightness4';
|
import Brightness4Icon from '@mui/icons-material/Brightness4';
|
||||||
import Brightness7Icon from '@mui/icons-material/Brightness7';
|
import Brightness7Icon from '@mui/icons-material/Brightness7';
|
||||||
import Cookies from 'js-cookie'
|
import Cookies from 'js-cookie'
|
||||||
import TerminalComponent from "./terminal";
|
|
||||||
|
|
||||||
const ColorModeContext = React.createContext({ toggleColorMode: () => { } });
|
const ColorModeContext = React.createContext({ toggleColorMode: () => { } });
|
||||||
|
|
||||||
@ -113,7 +112,6 @@ export default function App() {
|
|||||||
}),
|
}),
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
|
||||||
|
|
||||||
const theme = React.useMemo(() => createTheme(getDesignTokens(mode)), [mode]);
|
const theme = React.useMemo(() => createTheme(getDesignTokens(mode)), [mode]);
|
||||||
|
|
||||||
@ -131,7 +129,6 @@ export default function App() {
|
|||||||
<Route path='servers' element={<ServersBoard />} />
|
<Route path='servers' element={<ServersBoard />} />
|
||||||
<Route path='users' element={<UsersPage />} />
|
<Route path='users' element={<UsersPage />} />
|
||||||
<Route path='browsers' element={<BrowsersPage />} />
|
<Route path='browsers' element={<BrowsersPage />} />
|
||||||
<Route path='terminal' element={<TerminalComponent websocket={searchParams.get('ws')} />} />
|
|
||||||
<Route index element={<Navigate to='/servers' />} />
|
<Route index element={<Navigate to='/servers' />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
@ -264,12 +264,8 @@ export function ActionItem(p: { action: ActionInfo, identifierSubstring?: string
|
|||||||
setFormData(args.formData)
|
setFormData(args.formData)
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTerminalWindow(websocket: string){
|
|
||||||
window.open(`/terminal?ws=${encodeURIComponent(websocket)}`, 'Terminal', 'width=800,height=600');
|
|
||||||
}
|
|
||||||
|
|
||||||
return (<>
|
return (<>
|
||||||
<Button variant={p.variant} disabled={!isUserAllowed(user, p.action)} onClick={() => { if (p.onClick) { p.onClick() } p.action.response_action == 'Terminal'?createTerminalWindow(`ws${API_URL.slice("http".length)}${url}`):setForm(true) }} sx={p.sx}>{p.action.name}</Button >
|
<Button variant={p.variant} disabled={!isUserAllowed(user, p.action)} onClick={() => { if (p.onClick) { p.onClick() } p.action.response_action == 'Terminal'?setTerminal(`ws${API_URL.slice("http".length)}${url}`):setForm(true) }} sx={p.sx}>{p.action.name}</Button >
|
||||||
<Modal
|
<Modal
|
||||||
onClose={() => { setForm(false); setFormData({}); }}
|
onClose={() => { setForm(false); setFormData({}); }}
|
||||||
open={form}
|
open={form}
|
||||||
|
139
src/terminal.tsx
139
src/terminal.tsx
@ -1,83 +1,104 @@
|
|||||||
|
// terminal.tsx
|
||||||
// src/components/Terminal.tsx
|
// src/components/Terminal.tsx
|
||||||
import React, { useEffect, useRef } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import { Terminal } from 'xterm';
|
import { Terminal } from 'xterm';
|
||||||
import { FitAddon } from 'xterm-addon-fit';
|
import { FitAddon } from 'xterm-addon-fit';
|
||||||
import 'xterm/css/xterm.css';
|
import 'xterm/css/xterm.css';
|
||||||
|
|
||||||
|
const useTerminalResize = (terminalRef: React.RefObject<HTMLDivElement>, fitAddon: FitAddon, newWindow: Window | null) => {
|
||||||
const useTerminalResize = (terminalRef: React.RefObject<HTMLDivElement>, fitAddon: FitAddon) => {
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleResize = () => {
|
const handleResize = () => {
|
||||||
if (fitAddon && terminalRef.current) {
|
if (fitAddon && terminalRef.current) {
|
||||||
fitAddon.fit();
|
fitAddon.fit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (newWindow) {
|
||||||
|
newWindow.addEventListener('resize', handleResize);
|
||||||
|
} else {
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener('resize', handleResize);
|
|
||||||
|
|
||||||
// Fit the terminal initially
|
|
||||||
handleResize();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener('resize', handleResize);
|
|
||||||
};
|
|
||||||
}, [terminalRef, fitAddon]);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
handleResize();
|
||||||
|
|
||||||
function TerminalComponent (p: {websocket: string|null}) {
|
return () => {
|
||||||
const {websocket} = p
|
if (newWindow) {
|
||||||
|
newWindow.removeEventListener('resize', handleResize);
|
||||||
|
} else {
|
||||||
|
window.removeEventListener('resize', handleResize);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [terminalRef, fitAddon, newWindow]);
|
||||||
|
};
|
||||||
|
|
||||||
|
function TerminalComponent(p: { websocket: string | null }) {
|
||||||
|
const { websocket } = p;
|
||||||
const terminalRef = useRef<HTMLDivElement>(null);
|
const terminalRef = useRef<HTMLDivElement>(null);
|
||||||
const terminal = useRef<Terminal | null>(null);
|
const terminal = useRef<Terminal | null>(null);
|
||||||
const fitAddon = useRef<FitAddon | null>(null);
|
const fitAddon = useRef<FitAddon | null>(null);
|
||||||
|
const newWindow = useRef<Window | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (terminalRef.current) {
|
newWindow.current = window.open('', '', 'width=800,height=600');
|
||||||
terminal.current = new Terminal();
|
|
||||||
fitAddon.current = new FitAddon();
|
if (newWindow.current) {
|
||||||
terminal.current.loadAddon(fitAddon.current);
|
newWindow.current.document.title = "Terminal";
|
||||||
terminal.current.open(terminalRef.current);
|
const terminalDiv = newWindow.current.document.createElement('div');
|
||||||
fitAddon.current.fit();
|
terminalDiv.style.width = '100%';
|
||||||
if (websocket == null){
|
terminalDiv.style.height = '100%';
|
||||||
|
newWindow.current.document.body.appendChild(terminalDiv);
|
||||||
return ()=>{
|
|
||||||
terminal.current?.dispose();
|
terminalRef.current = terminalDiv;
|
||||||
|
|
||||||
|
if (terminalRef.current) {
|
||||||
|
terminal.current = new Terminal();
|
||||||
|
fitAddon.current = new FitAddon();
|
||||||
|
terminal.current.loadAddon(fitAddon.current);
|
||||||
|
terminal.current.open(terminalRef.current);
|
||||||
|
fitAddon.current.fit();
|
||||||
|
|
||||||
|
if (websocket == null) {
|
||||||
|
return () => {
|
||||||
|
terminal.current?.dispose();
|
||||||
|
newWindow.current?.close();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const socket = new WebSocket(websocket);
|
||||||
|
|
||||||
|
socket.onerror = (ev) => {
|
||||||
|
console.log(ev);
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.addEventListener('open', () => {
|
||||||
|
socket.send(JSON.stringify({ CommandType: 'resize', Arguments: `${terminal.current?.cols}x${terminal.current?.rows}` }));
|
||||||
|
});
|
||||||
|
|
||||||
|
terminal.current.onResize(({ cols, rows }) => {
|
||||||
|
socket.send(JSON.stringify({ CommandType: 'resize', Arguments: `${cols}x${rows}` }));
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.addEventListener('message', (event) => {
|
||||||
|
terminal.current?.write(JSON.parse(event.data));
|
||||||
|
});
|
||||||
|
|
||||||
|
terminal.current.onData((data) => {
|
||||||
|
socket.send(JSON.stringify({ CommandType: 'insert', Arguments: data }));
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
console.log("closed websocket");
|
||||||
|
terminal.current?.dispose();
|
||||||
|
socket.close();
|
||||||
|
newWindow.current?.close();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const socket = new WebSocket(websocket);
|
|
||||||
|
|
||||||
socket.onerror = (ev)=>{
|
|
||||||
console.log(ev)
|
|
||||||
}
|
|
||||||
|
|
||||||
socket.addEventListener('open', () => {
|
|
||||||
socket.send(JSON.stringify({CommandType: 'resize', Arguments: `${terminal.current?.cols}x${terminal.current?.rows}`}));
|
|
||||||
});
|
|
||||||
|
|
||||||
terminal.current.onResize(({cols, rows})=>{
|
|
||||||
socket.send(JSON.stringify({CommandType: 'resize', Arguments: `${cols}x${rows}`}));
|
|
||||||
})
|
|
||||||
|
|
||||||
socket.addEventListener('message', (event) => {
|
|
||||||
terminal.current?.write(JSON.parse(event.data));
|
|
||||||
});
|
|
||||||
|
|
||||||
terminal.current.onData((data) => {
|
|
||||||
socket.send(JSON.stringify({CommandType: 'insert', Arguments: data}));
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
console.log("closed websocket")
|
|
||||||
terminal.current?.dispose();
|
|
||||||
socket.close();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useTerminalResize(terminalRef, fitAddon.current!)
|
useTerminalResize(terminalRef, fitAddon.current!, newWindow.current);
|
||||||
|
|
||||||
return <div ref={terminalRef} style={{ width: '100%', height: '100%' }}></div>;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TerminalComponent;
|
export default TerminalComponent;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user