zack commited on
Commit
da79dee
β€’
1 Parent(s): 08f3702

πŸ”₯ chore(frontend): remove xterm.js component

Browse files

✨ feat(frontend): enhance ReactFlow environment

πŸ“¦ feat(frontend): add Proxmox component integration

frontend/src/components/Proxmox/proxmox.js ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useEffect, useRef } from 'react';
2
+ import { Terminal } from 'xterm';
3
+ import 'xterm/css/xterm.css';
4
+ import socket from './socket';
5
+
6
+ const ProxmoxVM = ({ vmAddress }) => {
7
+ const terminalRef = useRef(null);
8
+ const terminal = useRef(new Terminal());
9
+
10
+ useEffect(() => {
11
+ terminal.current.open(terminalRef.current);
12
+ terminal.current.writeln('Connecting to VM...');
13
+
14
+ socket.emit('fetchVmData', { vm_address: vmAddress });
15
+
16
+ socket.on('vmData', (data) => {
17
+ terminal.current.writeln(data);
18
+ });
19
+
20
+ return () => {
21
+ socket.off('vmData');
22
+ terminal.current.dispose();
23
+ };
24
+ }, [vmAddress]);
25
+
26
+ return <div ref={terminalRef} />;
27
+ };
28
+
29
+ export default ProxmoxVM;
frontend/src/components/Proxmox/socket.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ import io from "socket.io-client";
2
+ export const socket = io("http://localhost:5000");
3
+ export default socket;
frontend/src/components/Proxmox/xterm.js ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useEffect, useRef } from 'react';
2
+ import { Terminal } from 'xterm';
3
+ import './xterm.css';
4
+
5
+ const TerminalComponent = ({ socket }) => {
6
+ const terminalRef = useRef(null);
7
+ useEffect(() => {
8
+ const terminal = new Terminal();
9
+ terminal.open(terminalRef.current);
10
+
11
+ const ws = new WebSocket('ws://localhost:8080');
12
+ ws.onopen = () => {
13
+ console.log('Connected to WebSocket');
14
+ ws.send('fetchVmData'); // Request VM data on connection
15
+ };
16
+ ws.onmessage = (event) => {
17
+ const data = JSON.parse(event.data);
18
+ terminal.write(JSON.stringify(data, null, 2)); // Display VM data in terminal
19
+ };
20
+
21
+ return () => {
22
+ ws.close();
23
+ socket.off('data');
24
+ };
25
+ }, []);
26
+
27
+ return <div ref={terminalRef} />;
28
+ };
29
+
30
+ export default TerminalComponent;
frontend/src/components/ReactFlow/ReactFlowEnv.js CHANGED
@@ -17,9 +17,11 @@ import { useThemeDetector } from '../../helper/visual'
17
  import {CgMoreVerticalAlt} from 'react-icons/cg'
18
  import {BsFillEraserFill} from 'react-icons/bs'
19
  import {FaRegSave} from 'react-icons/fa'
 
20
 
21
  const NODE = {
22
  custom : CustomNodeIframe,
 
23
  }
24
 
25
  const EDGE = {
@@ -35,6 +37,7 @@ export default function ReactEnviorment() {
35
  const [reactFlowInstance, setReactFlowInstance] = useState(null);
36
  const reactFlowWrapper = useRef(null);
37
  const [tool, setTool] = useState(false)
 
38
 
39
  const deleteNodeContains = useCallback((id) => setNodes((nds) => nds.filter(n => !n.id.includes(`${id}-`))), [setNodes]);
40
  const deleteEdge = useCallback((id) => setEdges((eds) => eds.filter(e => e.id !== id)), [setEdges]);
@@ -134,19 +137,40 @@ export default function ReactEnviorment() {
134
  y: event.clientY - reactFlowBounds.top,
135
  });
136
 
137
- const newNode = {
138
- id: `${item.name}-${nodes.length+1}`,
139
- type,
140
- position,
141
- dragHandle : `#draggable`,
142
- data: { label: `${item.name}`, host : `${item.host}`, colour : `${style.colour}`, emoji : `${style.emoji}`, delete : deleteNode },
143
- };
144
-
145
- setNodes((nds) => nds.concat(newNode));
 
 
 
 
 
 
 
 
 
 
146
  }
147
  },
148
  [reactFlowInstance, nodes, deleteNode]);
149
 
 
 
 
 
 
 
 
 
 
 
 
150
  return (
151
  <div className={`${theme ? "dark" : ""}`}>
152
  <div className={` absolute text-center ${tool ? "h-[203.3333px]" : "h-[41px]"} overflow-hidden w-[41px] text-4xl top-4 right-5 z-50 cursor-default select-none bg-white dark:bg-stone-900 rounded-full border border-black dark:border-white duration-500`} >
@@ -155,6 +179,16 @@ export default function ReactEnviorment() {
155
  <FaRegSave title="Save" className={`mt-6 text-black dark:text-white ${tool ? "visible" : " invisible"} ml-auto mr-auto `} onClick={() => onSave()}/>
156
  <BsFillEraserFill title="Erase" className={`mt-6 text-black dark:text-white ml-auto mr-auto ${tool ? "visible" : " invisible"} `} onClick={() => onErase()}/>
157
  </div>
 
 
 
 
 
 
 
 
 
 
158
  <div className={`flex h-screen w-screen ${theme ? "dark" : ""} transition-all`}>
159
  <ReactFlowProvider>
160
  <Navbar onDelete={deleteNodeContains} colour={JSON.parse(localStorage.getItem('colour'))} emoji={JSON.parse(localStorage.getItem('emoji'))}/>
 
17
  import {CgMoreVerticalAlt} from 'react-icons/cg'
18
  import {BsFillEraserFill} from 'react-icons/bs'
19
  import {FaRegSave} from 'react-icons/fa'
20
+ import ProxmoxVM from '../Proxmox/proxmox.js';
21
 
22
  const NODE = {
23
  custom : CustomNodeIframe,
24
+ proxmoxVM: ProxmoxVM,
25
  }
26
 
27
  const EDGE = {
 
37
  const [reactFlowInstance, setReactFlowInstance] = useState(null);
38
  const reactFlowWrapper = useRef(null);
39
  const [tool, setTool] = useState(false)
40
+ const [showProxmoxForm, setShowProxmoxForm] = useState(false);
41
 
42
  const deleteNodeContains = useCallback((id) => setNodes((nds) => nds.filter(n => !n.id.includes(`${id}-`))), [setNodes]);
43
  const deleteEdge = useCallback((id) => setEdges((eds) => eds.filter(e => e.id !== id)), [setEdges]);
 
137
  y: event.clientY - reactFlowBounds.top,
138
  });
139
 
140
+ if (type === 'customProxmox') {
141
+ const newNode = {
142
+ id: `proxmox-vm-${nodes.length + 1}`,
143
+ type: 'customProxmox',
144
+ position,
145
+ data: { vmAddress: item.vmAddress },
146
+ };
147
+ setNodes((nds) => nds.concat(newNode));
148
+ } else {
149
+ const newNode = {
150
+ id: `${item.name}-${nodes.length+1}`,
151
+ type,
152
+ position,
153
+ dragHandle : `#draggable`,
154
+ data: { label: `${item.name}`, host : `${item.host}`, colour : `${style.colour}`, emoji : `${style.emoji}`, delete : deleteNode },
155
+ };
156
+
157
+ setNodes((nds) => nds.concat(newNode));
158
+ }
159
  }
160
  },
161
  [reactFlowInstance, nodes, deleteNode]);
162
 
163
+ const addProxmoxVMNode = (vmAddress) => {
164
+ const newNode = {
165
+ id: `proxmox-vm-${nodes.length + 1}`,
166
+ type: 'proxmoxVM',
167
+ position: { x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight },
168
+ data: { vmAddress },
169
+ };
170
+ setNodes((nds) => nds.concat(newNode));
171
+ setShowProxmoxForm(false);
172
+ };
173
+
174
  return (
175
  <div className={`${theme ? "dark" : ""}`}>
176
  <div className={` absolute text-center ${tool ? "h-[203.3333px]" : "h-[41px]"} overflow-hidden w-[41px] text-4xl top-4 right-5 z-50 cursor-default select-none bg-white dark:bg-stone-900 rounded-full border border-black dark:border-white duration-500`} >
 
179
  <FaRegSave title="Save" className={`mt-6 text-black dark:text-white ${tool ? "visible" : " invisible"} ml-auto mr-auto `} onClick={() => onSave()}/>
180
  <BsFillEraserFill title="Erase" className={`mt-6 text-black dark:text-white ml-auto mr-auto ${tool ? "visible" : " invisible"} `} onClick={() => onErase()}/>
181
  </div>
182
+ {showProxmoxForm && (
183
+ <form onSubmit={(e) => {
184
+ e.preventDefault();
185
+ addProxmoxVMNode(e.target.vmAddress.value);
186
+ }} className="absolute top-10 left-10 z-50">
187
+ <input name="vmAddress" type="text" placeholder="Enter Proxmox VM Address" required className="p-2"/>
188
+ <button type="submit" className="p-2 bg-blue-500 text-white">Add VM</button>
189
+ </form>
190
+ )}
191
+ <button onClick={() => setShowProxmoxForm(true)} className="absolute top-10 right-10 z-50 p-2 bg-green-500 text-white">Add Proxmox VM</button>
192
  <div className={`flex h-screen w-screen ${theme ? "dark" : ""} transition-all`}>
193
  <ReactFlowProvider>
194
  <Navbar onDelete={deleteNodeContains} colour={JSON.parse(localStorage.getItem('colour'))} emoji={JSON.parse(localStorage.getItem('emoji'))}/>