zack commited on
Commit
61accb8
β€’
1 Parent(s): 3fde1d6

πŸ”§ Update navbar and ReactFlowEnv components, πŸ“Έ Add new chatty image

Browse files
frontend/src/components/Navagation/navbar.js CHANGED
@@ -5,31 +5,31 @@ import { random_colour, random_emoji } from "../../helper/visual";
5
 
6
  import "../../css/dist/output.css"
7
 
8
- import { BsArrowLeftShort } from 'react-icons/bs';
9
- import { ReactComponent as ReactLogo } from '../../images/logo.svg'
10
- import chattyImage from '../../images/chatty.png';
11
 
12
- export default class Navbar extends Component {
13
- constructor(props) {
14
- super(props)
15
  this.temp_host = 0
16
  this.deleteNode = props.onDelete
17
  this.state = {
18
- open: true,
19
- menu: [],
20
- colour: props.colour || [],
21
- text: "",
22
- name: "",
23
- emoji: props.emoji || [],
24
- mode: false,
25
- modal: false,
26
- error: false
27
- }
28
-
29
  }
30
 
31
- componentDidMount() {
32
- this.fetch_classes()
33
 
34
  }
35
 
@@ -39,17 +39,17 @@ export default class Navbar extends Component {
39
  */
40
  fetch_classes = async () => {
41
  try {
42
- setInterval(async () => {
43
- await fetch("http://localhost:2000/api/open/ports", { method: 'GET', mode: 'cors', })
44
- .then(response => response.json())
45
- .then(data => {
46
- this.handelTabs(this.state.menu, data, data)
47
- this.setState({ menu: data })
48
- })
49
- .catch(error => { console.log(error) })
50
-
51
- }, 1000);
52
- } catch (e) {
53
  console.log(e)
54
  }
55
  }
@@ -59,34 +59,33 @@ export default class Navbar extends Component {
59
  */
60
  appendStreamNode = async (type) => {
61
  const pattern = {
62
- local: new RegExp('^https?://(localhost)(:[0-9]+)?(/)?$'),
63
- share: new RegExp('^https?://(?:[a-zA-Z0-9]+\\.gradio\\.live)/?$'),
64
  huggingFace: new RegExp('^https?://([a-zA-Z0-9-]+\\.hf\\.space)/?$'),
65
  proxmoxVNC: new RegExp('^wss?://([a-zA-Z0-9-]+\\.yourdomain\\.com)/?$') // Regex pattern for Proxmox VNC URLs
66
- }
67
 
68
  if (this.state.name.length > 20 ||
69
- this.state.text === "" ||
70
- this.state.menu.findIndex(element => { return element.name.toLowerCase() === this.state.name.toLowerCase() || element.host.includes(this.state.text) }) !== -1 ||
71
- this.state.text.includes(" ") ||
72
  (!pattern.local.test(this.state.text) &&
73
- !pattern.share.test(this.state.text) &&
74
- !pattern.huggingFace.test(this.state.text) &&
75
- !pattern.proxmoxVNC.test(this.state.text))) {
76
-
77
- this.setState({
78
- 'text': '',
79
- 'name': '',
80
- 'error': true
81
- })
82
- return
83
- }
84
- fetch(this.state.text, { method: "GET", mode: 'no-cors' }).then((re) => {
85
- fetch("http://localhost:2000/api/append/port", { method: 'POST', mode: 'cors', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ file: "", kwargs: { type: type }, name: this.state.name === "" ? `temp_class_${this.temp_host++}` : `${this.state.name}`, port: 0, host: this.state.text }) }).then(resp => {
86
- this.setState({ 'text': "", 'name': "", 'error': false, 'modal': false })
87
-
88
- }).catch(() => this.setState({ 'text': '', 'name': '', 'error': true, }))
89
- }).catch((err) => this.setState({ 'text': '', 'name': '', 'error': true, }))
90
  }
91
 
92
  /**
@@ -98,11 +97,11 @@ export default class Navbar extends Component {
98
  if (!proxmoxVncInfo) return null; // If no Proxmox VNC info, don't render anything
99
 
100
  return (
101
- <li onDragStart={(event) => this.onDragStart(event, 'proxmoxVNC', proxmoxVncInfo, -1)}
102
  className="text-white text-md flex flex-col text-center items-center cursor-grab shadow-lg p-5 px-2 mt-4 rounded-md hover:animate-pulse"
103
  draggable>
104
  <div className="absolute -mt-2 text-4xl opacity-60 z-10">{random_emoji()}</div>
105
- <h4 className="max-w-full font-sans text-blue-50 leading-tight font-bold text-xl flex-1 z-20" style={{ "textShadow": "0px 1px 2px rgba(0, 0, 0, 0.25)" }}>
106
  Proxmox VNC
107
  </h4>
108
  </li>
@@ -114,10 +113,8 @@ export default class Navbar extends Component {
114
  * @param {*} bool boolean of the current state of the modal
115
  */
116
  handelModal = (bool) => {
117
- this.setState({
118
- 'error': !bool ? false : this.state.error,
119
- 'modal': bool
120
- })
121
  }
122
 
123
  /**
@@ -129,10 +126,10 @@ export default class Navbar extends Component {
129
  */
130
  onDragStart = (event, nodeType, item, index) => {
131
  event.dataTransfer.setData('application/reactflow', nodeType);
132
- event.dataTransfer.setData('application/style', JSON.stringify({ colour: this.state.colour[index], emoji: this.state.emoji[index] }))
133
- event.dataTransfer.setData('application/item', JSON.stringify(item))
134
  event.dataTransfer.effectAllowed = 'move';
135
- };
136
 
137
  /**
138
  * droped event that occurs when the user drops the Tab within the tash div.
@@ -142,11 +139,11 @@ export default class Navbar extends Component {
142
  */
143
  onDragDrop = (e) => {
144
  e.preventDefault();
145
- var item = JSON.parse(e.dataTransfer.getData('application/item'));
146
- fetch("http://localhost:2000/api/remove/port", { method: "POST", mode: 'cors', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(item) }).then((re) => {
147
  this.deleteNode(item.name)
148
  })
149
-
150
  }
151
 
152
  /**
@@ -161,37 +158,37 @@ export default class Navbar extends Component {
161
  var c = []
162
  var j = []
163
  if (d.length - e.length === 0) return
164
- else if (d.length - e.length < 0) {
165
  var a = this.state.menu.filter(item => e.includes(item)) // get the items not in menu anymore
166
  c = this.state.colour
167
  j = this.state.emoji
168
- for (var k = 0; k < d.length; k++) {
169
  c.splice(this.state.menu.indexOf(a[k]), 1)
170
  j.splice(this.state.menu.indexOf(a[k]), 1)
171
  }
172
- this.setState({ 'colour': c, 'emoji': j })
173
- } else {
174
  //append new colours
175
- for (var i = 0; i < d.length; i++) {
176
- c.push(random_colour(i === 0 ? null : c[i - 1]));
177
- j.push(random_emoji(i === 0 ? null : c[i - 1]));
178
-
179
  }
180
  const colour = [...this.state.colour]
181
- const emoji = [...this.state.emoji]
182
- this.setState({ 'colour': [...colour, ...c], 'emoji': [...emoji, ...j], })
183
  }
184
  }
185
 
186
  handelError = (boolean) => {
187
- this.setState({ 'error': boolean })
188
  }
189
 
190
  /**
191
  * handel navagation open and close function
192
  */
193
  handelNavbar = () => {
194
- this.setState({ 'open': !this.state.open })
195
  }
196
 
197
  /**
@@ -200,7 +197,7 @@ export default class Navbar extends Component {
200
  * @param {*} type : text | name string that set the changed value of the input to the current value
201
  */
202
  updateText = (e, type) => {
203
- this.setState({ [`${type}`]: e.target.value })
204
  }
205
 
206
  /**
@@ -209,62 +206,59 @@ export default class Navbar extends Component {
209
  * @param {*} index : current index with in the list
210
  * @returns div component that contians infomation of gradio
211
  */
212
- subComponents(item, index) {
 
 
 
 
 
213
 
214
- return (<>
215
- <li key={`${index}-li`} onDragStart={(event) => this.onDragStart(event, 'custom', item, index)}
216
- className={` text-white text-md flex flex-col text-center items-center cursor-grab shadow-lg
217
- p-5 px-2 mt-4 rounded-md ${this.state.open ? `hover:animate-pulse ${this.state.colour[index] === null ? "" : this.state.colour[index]} ` : `hidden`} break-all -z-20`} draggable>
218
 
219
- <div key={`${index}-div`} className=" absolute -mt-2 text-4xl opacity-60 z-10 ">{`${this.state.emoji[index] === null ? "" : this.state.emoji[index]}`}</div>
220
- <h4 key={`${index}-h4`} className={` max-w-full font-sans text-blue-50 leading-tight font-bold text-xl flex-1 z-20 ${this.state.open ? "" : "hidden"}`} style={{ "textShadow": "0px 1px 2px rgba(0, 0, 0, 0.25)" }} >{`${item.name}`} </h4>
221
-
222
- </li >
223
 
224
  </>)
225
  }
226
 
227
 
228
- render() {
229
-
230
  return (<div>
231
-
232
  <div className={`z-10 flex-1 float-left bg-white dark:bg-stone-900 h-screen p-5 pt-8 ${this.state.open ? "lg:w-72 md:64 sm:w-60" : "w-10"} duration-300 absolute shadow-2xl border-black border-r-[1px] dark:border-white dark:text-white`} >
233
 
234
- <BsArrowLeftShort onClick={this.handelNavbar} className={` bg-white text-Retro-darl-blue text-3xl rounded-full absolute -right-3 top-9 border border-black cursor-pointer ${!this.state.open && 'rotate-180'} dark:border-white duration-300 dark:text-white dark:bg-stone-900 `} />
235
- <div className="inline-flex w-full">
236
- <img src={chattyImage} alt="Chat'nFace Logo" className={`h-12 w-auto ${this.state.open ? "visible" : "hidden"}`} /> {/* Display the image */}
237
- <h1 className={`font-sans font-bold text-lg ${this.state.open ? "" : "hidden"} duration-500 ml-auto mr-auto`}>Chat-nFace</h1>
238
- </div>
239
  <div className="inline-flex w-full">
240
  <h1 className={`font-sans font-bold text-lg ${this.state.open ? "" : "hidden"} duration-500 ml-auto mr-auto`}>Chat-nFace</h1>
241
  </div>
242
 
243
- <div className={`rounded-md text-center ${this.state.open ? "" : "px-0"} py-3`} onClick={() => { this.handelModal(true) }}>
244
  <div className={` text-center bg-transparent w-full h-10 border border-slate-300 hover:border-Retro-purple hover:animate-pulse border-dashed rounded-md py-2 pl-5 ${this.state.open ? "pr-3" : "hidden"} shadow-sm sm:text-sm`}>
245
- <Icon className=" block mr-auto ml-auto" name="plus" />
246
  </div>
247
  </div>
248
- <Import open={this.state.modal}
249
- quitHandeler={this.handelModal}
250
- textHandler={this.updateText}
251
- appendHandler={this.appendStreamNode}
252
- handelError={this.handelError}
253
- catch={this.state.error} />
254
-
255
  <div className=" relative z-10 h-auto overflow-auto pt-4">
256
  <ul className="pt-2">
257
- {this.state.menu.map((menu, index) => { return this.subComponents(menu, index) })}
258
  </ul>
259
  </div>
260
 
261
- <div className={`${this.state.open ? "" : "hidden"} absolute bottom-0 left-0 w-full text-center p-5`} onDragOver={(e) => { e.preventDefault() }} onDrop={(e) => { this.onDragDrop(e) }}>
262
  <div className={` text-center bg-transparent w-full h-10 border border-red-600 border-dashed rounded-md py-2 pl-5 p-4 ${this.state.open ? "pr-3" : "hidden"} shadow-sm sm:text-sm`}>
263
- <Icon name='trash alternate' />
264
  </div>
265
  </div>
266
  </div>
267
-
268
  </div>)
269
  }
270
  }
 
5
 
6
  import "../../css/dist/output.css"
7
 
8
+ import {BsArrowLeftShort} from 'react-icons/bs';
9
+ import {ReactComponent as ReactLogo} from '../../images/logo.svg'
10
+ import chattyImage from '../../images/chatty.png'; // Import the image
11
 
12
+ export default class Navbar extends Component{
13
+ constructor(props){
14
+ super(props)
15
  this.temp_host = 0
16
  this.deleteNode = props.onDelete
17
  this.state = {
18
+ open : true,
19
+ menu : [],
20
+ colour : props.colour || [],
21
+ text : "",
22
+ name : "",
23
+ emoji : props.emoji || [],
24
+ mode : false,
25
+ modal : false,
26
+ error : false
27
+ }
28
+
29
  }
30
 
31
+ componentDidMount(){
32
+ this.fetch_classes()
33
 
34
  }
35
 
 
39
  */
40
  fetch_classes = async () => {
41
  try {
42
+ setInterval( async () => {
43
+ await fetch("http://localhost:2000/api/open/ports", { method: 'GET', mode : 'cors',})
44
+ .then(response => response.json())
45
+ .then(data => {
46
+ this.handelTabs(this.state.menu,data, data)
47
+ this.setState({menu : data})
48
+ })
49
+ .catch(error => {console.log(error)})
50
+
51
+ },1000);
52
+ }catch(e){
53
  console.log(e)
54
  }
55
  }
 
59
  */
60
  appendStreamNode = async (type) => {
61
  const pattern = {
62
+ local : new RegExp('^https?://(localhost)(:[0-9]+)?(/)?$'),
63
+ share : new RegExp('^https?://(?:[a-zA-Z0-9]+\\.gradio\\.live)/?$'),
64
  huggingFace: new RegExp('^https?://([a-zA-Z0-9-]+\\.hf\\.space)/?$'),
65
  proxmoxVNC: new RegExp('^wss?://([a-zA-Z0-9-]+\\.yourdomain\\.com)/?$') // Regex pattern for Proxmox VNC URLs
66
+ }
67
 
68
  if (this.state.name.length > 20 ||
69
+ this.state.text === ""||
70
+ this.state.menu.findIndex(element => {return element.name.toLowerCase() === this.state.name.toLowerCase() || element.host.includes(this.state.text) }) !== -1 ||
71
+ this.state.text.includes(" ") ||
72
  (!pattern.local.test(this.state.text) &&
73
+ !pattern.share.test(this.state.text) &&
74
+ !pattern.huggingFace.test(this.state.text) &&
75
+ !pattern.proxmoxVNC.test(this.state.text))){
76
+
77
+ this.setState({
78
+ 'text': '',
79
+ 'name': '',
80
+ 'error': true})
81
+ return
82
+ }
83
+ fetch(this.state.text, {method: "GET", mode: 'no-cors'}).then((re) => {
84
+ fetch("http://localhost:2000/api/append/port", {method: 'POST', mode : 'cors', headers : { 'Content-Type' : 'application/json' }, body: JSON.stringify({file : "", kwargs : { type : type }, name : this.state.name === "" ?`temp_class_${this.temp_host++}` : `${this.state.name}`, port: 0 , host : this.state.text}) }).then(resp => {
85
+ this.setState({'text': "",'name' : "",'error' : false,'modal' : false })
86
+
87
+ }).catch(() => this.setState({'text': '', 'name' : '', 'error' : true, }))
88
+ }).catch((err)=> this.setState({'text': '','name' : '', 'error' : true,}))
 
89
  }
90
 
91
  /**
 
97
  if (!proxmoxVncInfo) return null; // If no Proxmox VNC info, don't render anything
98
 
99
  return (
100
+ <li onDragStart={(event) => this.onDragStart(event, 'proxmoxVNC', proxmoxVncInfo, -1)}
101
  className="text-white text-md flex flex-col text-center items-center cursor-grab shadow-lg p-5 px-2 mt-4 rounded-md hover:animate-pulse"
102
  draggable>
103
  <div className="absolute -mt-2 text-4xl opacity-60 z-10">{random_emoji()}</div>
104
+ <h4 className="max-w-full font-sans text-blue-50 leading-tight font-bold text-xl flex-1 z-20" style={{"textShadow": "0px 1px 2px rgba(0, 0, 0, 0.25)"}}>
105
  Proxmox VNC
106
  </h4>
107
  </li>
 
113
  * @param {*} bool boolean of the current state of the modal
114
  */
115
  handelModal = (bool) => {
116
+ this.setState({'error' : !bool ? false : this.state.error ,
117
+ 'modal' : bool})
 
 
118
  }
119
 
120
  /**
 
126
  */
127
  onDragStart = (event, nodeType, item, index) => {
128
  event.dataTransfer.setData('application/reactflow', nodeType);
129
+ event.dataTransfer.setData('application/style', JSON.stringify({colour : this.state.colour[index], emoji : this.state.emoji[index] }))
130
+ event.dataTransfer.setData('application/item', JSON.stringify(item))
131
  event.dataTransfer.effectAllowed = 'move';
132
+ };
133
 
134
  /**
135
  * droped event that occurs when the user drops the Tab within the tash div.
 
139
  */
140
  onDragDrop = (e) => {
141
  e.preventDefault();
142
+ var item = JSON.parse(e.dataTransfer.getData('application/item'));
143
+ fetch("http://localhost:2000/api/remove/port", {method : "POST", mode: 'cors', headers : { 'Content-Type' : 'application/json' }, body: JSON.stringify(item) }).then((re)=>{
144
  this.deleteNode(item.name)
145
  })
146
+
147
  }
148
 
149
  /**
 
158
  var c = []
159
  var j = []
160
  if (d.length - e.length === 0) return
161
+ else if(d.length - e.length < 0){
162
  var a = this.state.menu.filter(item => e.includes(item)) // get the items not in menu anymore
163
  c = this.state.colour
164
  j = this.state.emoji
165
+ for(var k=0; k < d.length; k++){
166
  c.splice(this.state.menu.indexOf(a[k]), 1)
167
  j.splice(this.state.menu.indexOf(a[k]), 1)
168
  }
169
+ this.setState({'colour' : c, 'emoji' : j})
170
+ }else{
171
  //append new colours
172
+ for(var i =0; i < d.length; i++){
173
+ c.push(random_colour(i === 0 ? null : c[i-1]));
174
+ j.push(random_emoji(i === 0 ? null : c[i-1]));
175
+
176
  }
177
  const colour = [...this.state.colour]
178
+ const emoji = [...this.state.emoji]
179
+ this.setState({'colour' : [...colour, ...c], 'emoji' : [...emoji, ...j],})
180
  }
181
  }
182
 
183
  handelError = (boolean) => {
184
+ this.setState({'error' : boolean})
185
  }
186
 
187
  /**
188
  * handel navagation open and close function
189
  */
190
  handelNavbar = () => {
191
+ this.setState({'open' : !this.state.open})
192
  }
193
 
194
  /**
 
197
  * @param {*} type : text | name string that set the changed value of the input to the current value
198
  */
199
  updateText = (e, type) => {
200
+ this.setState({[`${type}`] : e.target.value })
201
  }
202
 
203
  /**
 
206
  * @param {*} index : current index with in the list
207
  * @returns div component that contians infomation of gradio
208
  */
209
+ subComponents(item, index){
210
+
211
+ return(<>
212
+ <li key={`${index}-li`} onDragStart={(event) => this.onDragStart(event, 'custom', item, index)}
213
+ className={` text-white text-md flex flex-col text-center items-center cursor-grab shadow-lg
214
+ p-5 px-2 mt-4 rounded-md ${ this.state.open ? `hover:animate-pulse ${this.state.colour[index] === null ? "" : this.state.colour[index]} ` : `hidden`} break-all -z-20`} draggable>
215
 
216
+ <div key={`${index}-div`} className=" absolute -mt-2 text-4xl opacity-60 z-10 ">{`${this.state.emoji[index] === null ? "" : this.state.emoji[index]}`}</div>
217
+ <h4 key={`${index}-h4`} className={` max-w-full font-sans text-blue-50 leading-tight font-bold text-xl flex-1 z-20 ${this.state.open ? "" : "hidden"}`} style={{"textShadow" : "0px 1px 2px rgba(0, 0, 0, 0.25)"}} >{`${item.name}`} </h4>
 
 
218
 
219
+ </li >
 
 
 
220
 
221
  </>)
222
  }
223
 
224
 
225
+ render(){
226
+
227
  return (<div>
228
+
229
  <div className={`z-10 flex-1 float-left bg-white dark:bg-stone-900 h-screen p-5 pt-8 ${this.state.open ? "lg:w-72 md:64 sm:w-60" : "w-10"} duration-300 absolute shadow-2xl border-black border-r-[1px] dark:border-white dark:text-white`} >
230
 
231
+ <BsArrowLeftShort onClick={this.handelNavbar} className={` bg-white text-Retro-darl-blue text-3xl rounded-full absolute -right-3 top-9 border border-black cursor-pointer ${!this.state.open && 'rotate-180'} dark:border-white duration-300 dark:text-white dark:bg-stone-900 `}/>
232
+
 
 
 
233
  <div className="inline-flex w-full">
234
  <h1 className={`font-sans font-bold text-lg ${this.state.open ? "" : "hidden"} duration-500 ml-auto mr-auto`}>Chat-nFace</h1>
235
  </div>
236
 
237
+ <div className={`rounded-md text-center ${this.state.open ? "" : "px-0"} py-3`} onClick={() => {this.handelModal(true)}}>
238
  <div className={` text-center bg-transparent w-full h-10 border border-slate-300 hover:border-Retro-purple hover:animate-pulse border-dashed rounded-md py-2 pl-5 ${this.state.open ? "pr-3" : "hidden"} shadow-sm sm:text-sm`}>
239
+ <Icon className=" block mr-auto ml-auto" name="plus"/>
240
  </div>
241
  </div>
242
+ <Import open={this.state.modal}
243
+ quitHandeler={this.handelModal}
244
+ textHandler={this.updateText}
245
+ appendHandler={this.appendStreamNode}
246
+ handelError={this.handelError}
247
+ catch={this.state.error}/>
248
+
249
  <div className=" relative z-10 h-auto overflow-auto pt-4">
250
  <ul className="pt-2">
251
+ {this.state.menu.map((menu, index) => {return this.subComponents(menu, index)})}
252
  </ul>
253
  </div>
254
 
255
+ <div className={`${this.state.open ? "" : "hidden"} absolute bottom-0 left-0 w-full text-center p-5`} onDragOver={(e)=> {e.preventDefault()}} onDrop={(e)=>{this.onDragDrop(e)}}>
256
  <div className={` text-center bg-transparent w-full h-10 border border-red-600 border-dashed rounded-md py-2 pl-5 p-4 ${this.state.open ? "pr-3" : "hidden"} shadow-sm sm:text-sm`}>
257
+ <Icon name='trash alternate' />
258
  </div>
259
  </div>
260
  </div>
261
+
262
  </div>)
263
  }
264
  }
frontend/src/components/ReactFlow/ReactFlowEnv.js CHANGED
@@ -57,33 +57,33 @@ export default function ReactEnviorment() {
57
  restore();
58
  },[deleteNode, deleteEdge]);
59
 
60
- const handleAddProxmoxVnc = async ({ vmid, node }) => {
61
- const response = await fetch('http://localhost:5000/api/proxmox/vnc', {
62
- method: 'POST',
63
- headers: { 'Content-Type': 'application/json' },
64
- body: JSON.stringify({ vmid, node }),
65
- });
66
- const data = await response.json();
67
- // Use data.iframe_src to create a new node in React Flow
68
- const newNode = {
69
- id: `proxmox-vnc-${nodes.length + 1}`,
70
- type: 'custom',
71
- position: reactFlowInstance.project({ x: 0, y: 0 }),
72
- data: { label: `Proxmox VM ${vmid}`, url: data.iframe_src },
73
- };
74
- setNodes((nds) => nds.concat(newNode));
75
- };
76
-
77
- const handleAddEmbed = useCallback((embedData) => {
78
- const newNode = {
79
- id: `embed-${nodes.length + 1}`,
80
- type: 'embed',
81
- position: reactFlowInstance.project({ x: 0, y: 0 }), // Adjust position as needed
82
- data: { url: embedData.url, width: embedData.width || '100%', height: embedData.height || '400px' },
83
- };
84
- setNodes((nds) => nds.concat(newNode));
85
- console.log(`Adding embed with URL: ${embedData.url} and Label: ${embedData.label}`);
86
- }, [nodes, reactFlowInstance]);
87
 
88
  const onNodesChange = useCallback(
89
  (changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
@@ -197,16 +197,16 @@ export default function ReactEnviorment() {
197
  },
198
  [reactFlowInstance, nodes, deleteNode]);
199
 
200
- const addProxmoxVMNode = (vmAddress) => {
201
- const newNode = {
202
- id: `proxmox-vm-${nodes.length + 1}`,
203
- type: 'proxmoxVM',
204
- position: { x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight },
205
- data: { vmAddress },
206
- };
207
- setNodes((nds) => nds.concat(newNode));
208
- setShowProxmoxForm(false);
209
- };
210
 
211
  return (
212
  <div className={`${theme ? "dark" : ""}`}>
@@ -216,7 +216,6 @@ export default function ReactEnviorment() {
216
  <FaRegSave title="Save" className={`mt-6 text-black dark:text-white ${tool ? "visible" : " invisible"} ml-auto mr-auto `} onClick={() => onSave()}/>
217
  <BsFillEraserFill title="Erase" className={`mt-6 text-black dark:text-white ml-auto mr-auto ${tool ? "visible" : " invisible"} `} onClick={() => onErase()}/>
218
  </div>
219
- <button onClick={() => setShowProxmoxForm(true)} className="absolute top-10 right-10 z-50 p-2 bg-green-500 text-white">Add Proxmox VM</button>
220
  <div className={`flex h-screen w-screen ${theme ? "dark" : ""} transition-all`}>
221
  <ReactFlowProvider>
222
  <Navbar onDelete={deleteNodeContains} colour={JSON.parse(localStorage.getItem('colour'))} emoji={JSON.parse(localStorage.getItem('emoji'))} nodes={nodes}/>
@@ -231,3 +230,4 @@ export default function ReactEnviorment() {
231
  </div>
232
  );
233
  }
 
 
57
  restore();
58
  },[deleteNode, deleteEdge]);
59
 
60
+ // const handleAddProxmoxVnc = async ({ vmid, node }) => {
61
+ // const response = await fetch('http://localhost:5000/api/proxmox/vnc', {
62
+ // method: 'POST',
63
+ // headers: { 'Content-Type': 'application/json' },
64
+ // body: JSON.stringify({ vmid, node }),
65
+ // });
66
+ // const data = await response.json();
67
+ // // Use data.iframe_src to create a new node in React Flow
68
+ // const newNode = {
69
+ // id: `proxmox-vnc-${nodes.length + 1}`,
70
+ // type: 'custom',
71
+ // position: reactFlowInstance.project({ x: 0, y: 0 }),
72
+ // data: { label: `Proxmox VM ${vmid}`, url: data.iframe_src },
73
+ // };
74
+ // setNodes((nds) => nds.concat(newNode));
75
+ // };
76
+
77
+ // const handleAddEmbed = useCallback((embedData) => {
78
+ // const newNode = {
79
+ // id: `embed-${nodes.length + 1}`,
80
+ // type: 'embed',
81
+ // position: reactFlowInstance.project({ x: 0, y: 0 }), // Adjust position as needed
82
+ // data: { url: embedData.url, width: embedData.width || '100%', height: embedData.height || '400px' },
83
+ // };
84
+ // setNodes((nds) => nds.concat(newNode));
85
+ // console.log(`Adding embed with URL: ${embedData.url} and Label: ${embedData.label}`);
86
+ // }, [nodes, reactFlowInstance]);
87
 
88
  const onNodesChange = useCallback(
89
  (changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
 
197
  },
198
  [reactFlowInstance, nodes, deleteNode]);
199
 
200
+ // const addProxmoxVMNode = (vmAddress) => {
201
+ // const newNode = {
202
+ // id: `proxmox-vm-${nodes.length + 1}`,
203
+ // type: 'proxmoxVM',
204
+ // position: { x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight },
205
+ // data: { vmAddress },
206
+ // };
207
+ // setNodes((nds) => nds.concat(newNode));
208
+ // setShowProxmoxForm(false);
209
+ // };
210
 
211
  return (
212
  <div className={`${theme ? "dark" : ""}`}>
 
216
  <FaRegSave title="Save" className={`mt-6 text-black dark:text-white ${tool ? "visible" : " invisible"} ml-auto mr-auto `} onClick={() => onSave()}/>
217
  <BsFillEraserFill title="Erase" className={`mt-6 text-black dark:text-white ml-auto mr-auto ${tool ? "visible" : " invisible"} `} onClick={() => onErase()}/>
218
  </div>
 
219
  <div className={`flex h-screen w-screen ${theme ? "dark" : ""} transition-all`}>
220
  <ReactFlowProvider>
221
  <Navbar onDelete={deleteNodeContains} colour={JSON.parse(localStorage.getItem('colour'))} emoji={JSON.parse(localStorage.getItem('emoji'))} nodes={nodes}/>
 
230
  </div>
231
  );
232
  }
233
+
{images β†’ frontend/src/images}/chatty.png RENAMED
File without changes