Spaces:
Configuration error
Configuration error
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 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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'))}/>
|