From 40f4fa3ee40f7db75f783d8e4e5bcb45528c885a Mon Sep 17 00:00:00 2001 From: ACoolName Date: Mon, 27 May 2024 00:34:42 +0300 Subject: [PATCH] test add xtermjs --- package-lock.json | 19 +++++++++++++++++- package.json | 4 +++- src/actions.tsx | 19 +++++++++++++----- src/common.tsx | 16 ++++++++++++--- src/terminal.tsx | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 src/terminal.tsx diff --git a/package-lock.json b/package-lock.json index 9e748f5..5fb8af3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,9 @@ "react-scripts": "5.0.1", "serve": "^14.2.1", "typescript": "^4.9.5", - "web-vitals": "^2.1.4" + "web-vitals": "^2.1.4", + "xterm": "^5.3.0", + "xterm-addon-fit": "^0.8.0" } }, "node_modules/@adobe/css-tools": { @@ -17952,6 +17954,21 @@ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, + "node_modules/xterm": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.3.0.tgz", + "integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==", + "deprecated": "This package is now deprecated. Move to @xterm/xterm instead." + }, + "node_modules/xterm-addon-fit": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.8.0.tgz", + "integrity": "sha512-yj3Np7XlvxxhYF/EJ7p3KHaMt6OdwQ+HDu573Vx1lRXsVxOcnVJs51RgjZOouIZOczTsskaS+CpXspK81/DLqw==", + "deprecated": "This package is now deprecated. Move to @xterm/addon-fit instead.", + "peerDependencies": { + "xterm": "^5.0.0" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 02a7044..438013c 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,9 @@ "react-scripts": "5.0.1", "serve": "^14.2.1", "typescript": "^4.9.5", - "web-vitals": "^2.1.4" + "web-vitals": "^2.1.4", + "xterm": "^5.3.0", + "xterm-addon-fit": "^0.8.0" }, "scripts": { "start": "react-scripts start", diff --git a/src/actions.tsx b/src/actions.tsx index 3c01b9f..dd48996 100644 --- a/src/actions.tsx +++ b/src/actions.tsx @@ -522,9 +522,9 @@ export const SERVER_ACTIONS: ActionInfo[] = [ type: "array", title: "Default Ports", items: - { - "$ref": "#/definitions/Port-Input" - } + { + "$ref": "#/definitions/Port-Input" + } }, DefaultCommand: { @@ -537,7 +537,7 @@ export const SERVER_ACTIONS: ActionInfo[] = [ } }, definitions: definitions, - + }, }, { @@ -571,7 +571,16 @@ export const SERVER_ACTIONS: ActionInfo[] = [ title: "Set User Permissions", definitions: definitions, }, - } + }, + { + name: "Start", + args: { + }, + requestType: "post", + endpoint: "/servers/{server_id}/attach", + permissions: Permission.RunCommand, + response_action: "Ignore" + }, ] export const CREATE_SERVER_ACTION: ActionInfo = { diff --git a/src/common.tsx b/src/common.tsx index b29ff07..4e731fc 100644 --- a/src/common.tsx +++ b/src/common.tsx @@ -16,6 +16,8 @@ import Popper from '@mui/material/Popper'; import MenuItem from '@mui/material/MenuItem'; import MenuList from '@mui/material/MenuList'; import { Permission } from "./actions"; +import { Terminal } from "xterm"; +import TerminalComponent from "./terminal"; export const apiAuthenticatedContext: Context<[boolean, Dispatch]> = createContext([false, (value: boolean) => {}] as [boolean, Dispatch]) @@ -216,12 +218,12 @@ export function ActionItem(p: { action: ActionInfo, identifierSubstring?: string const user = useContext(UserInfoContext) const [form, setForm] = useState(false); + const [terminal, setTerminal] = useState(null as string|null); const [formData, setFormData]: [RJSFSchema, Dispatch] = useState({}) - console.log(formData) + const url = p.action.endpoint.replaceAll(`{${identifierSubstring}}`, actionIdentifier) function handleSubmit() { - let url = p.action.endpoint.replaceAll(`{${identifierSubstring}}`, actionIdentifier) let promise: Promise>|null = null switch (p.action.requestType) { case 'post': { @@ -263,7 +265,7 @@ export function ActionItem(p: { action: ActionInfo, identifierSubstring?: string } return (<> - + { setForm(false); setFormData({}); }} open={form} @@ -272,6 +274,14 @@ export function ActionItem(p: { action: ActionInfo, identifierSubstring?: string
+ { setTerminal(null); }} + open={terminal != null} + > + + + + ) } diff --git a/src/terminal.tsx b/src/terminal.tsx new file mode 100644 index 0000000..1172429 --- /dev/null +++ b/src/terminal.tsx @@ -0,0 +1,51 @@ +// src/components/Terminal.tsx +import React, { useEffect, useRef } from 'react'; +import { Terminal } from 'xterm'; +import { FitAddon } from 'xterm-addon-fit'; +import 'xterm/css/xterm.css'; + +function TerminalComponent (p: {websocket: string|null}) { + const {websocket} = p + const terminalRef = useRef(null); + const terminal = useRef(null); + const fitAddon = useRef(null); + + useEffect(() => { + 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(); + } + } + + const socket = new WebSocket(websocket); + + socket.addEventListener('open', () => { + terminal.current?.write('Connected to the WebSocket server\r\n'); + }); + + socket.addEventListener('message', (event) => { + terminal.current?.write(event.data); + }); + + terminal.current.onData((data) => { + socket.send(data); + }); + + return () => { + terminal.current?.dispose(); + socket.close(); + }; + } + }, []); + + return
; +}; + +export default TerminalComponent;