LucaVivona commited on
Commit
c2ebfb9
β€’
1 Parent(s): 16543f4

Save Board πŸ’Ύ

Browse files
frontend/src/components/Navagation/navbar.js CHANGED
@@ -8,19 +8,19 @@ import { Message, Header, Modal, Button, Icon } from 'semantic-ui-react'
8
  export default class Navbar extends Component{
9
  constructor(props){
10
  super(props)
11
- this.fetch_classes()
12
  this.temp_host = 0
13
  this.deleteNode = props.onDelete
14
  this.state = {open : true,
15
  menu : [],
16
- colour : [],
17
  text : "",
18
  name : "",
19
- emoji : [],
20
  mode : false,
21
  modal : false,
22
  error : false
23
  }
 
24
  }
25
 
26
 
@@ -79,7 +79,7 @@ export default class Navbar extends Component{
79
  }
80
 
81
  fetch(this.state.text, {method : "GET", mode: 'no-cors'}).then((re) => {
82
- console.log(re)
83
  fetch("http://localhost:2000/api/append/port", {method: 'POST', mode : 'cors', headers : { 'Content-Type' : 'application/json' }, body: JSON.stringify({file : "", kwargs : {}, name : this.state.name === "" ?`temp_class_${this.temp_host++}` : `${this.state.name}`, port: 0 , host : this.state.text}) }).then(resp => {
84
  this.setState({open : this.state.open,
85
  menu : this.state.menu,
@@ -99,7 +99,7 @@ export default class Navbar extends Component{
99
  error : true,
100
  modal : this.state.modal }))
101
  }).catch((err)=>{
102
- console.log(err)
103
  this.setState({open : this.state.open,
104
  menu : this.state.menu,
105
  text: '',
@@ -135,7 +135,7 @@ export default class Navbar extends Component{
135
  */
136
  onDragStart = (event, nodeType, item, index) => {
137
  event.dataTransfer.setData('application/reactflow', nodeType);
138
- event.dataTransfer.setData('application/colour', this.state.colour[index])
139
  event.dataTransfer.setData('application/item', JSON.stringify(item))
140
  event.dataTransfer.effectAllowed = 'move';
141
  };
@@ -161,7 +161,10 @@ export default class Navbar extends Component{
161
  * @param {*} d integer variable of the diffence between the current menu and new menu updated ment
162
  */
163
  hanelTabs = (e, d) => {
164
-
 
 
 
165
  // if less then 0 we must remove colour's and emoji's
166
  // get index of the object
167
  // remove
@@ -178,6 +181,7 @@ export default class Navbar extends Component{
178
  this.setState({open : this.state.open, menu : e, text: this.state.text, name: this.state.name, colour : c, emoji : j, error : this.state.error, modal : this.state.modal })
179
  }else{
180
  //append new colours
 
181
  for(var i =0; i < d; i++){
182
  c.push(random_colour(i === 0 ? null : c[i-1]));
183
  j.push(random_emoji(i === 0 ? null : c[i-1]));
@@ -187,13 +191,6 @@ export default class Navbar extends Component{
187
  }
188
  }
189
 
190
- /**
191
- * Append a new colour, and emoji to the colour and emoji list with in the state of the component
192
- */
193
- appendTabs = () => {
194
- this.setState({open : this.state.open, menu : this.state.menu, text: this.state.text, name: this.state.name, colour : [...this.state.colour, random_colour(this.state.colour[this.state.colour.length - 1] )] , emoji : [...this.state.emoji, random_emoji(this.state.emoji[this.state.emoji.length - 1] )], error : this.state.error, modal : this.state.modal })
195
- }
196
-
197
  /**
198
  * handel navagation open and close function
199
  */
@@ -224,7 +221,7 @@ export default class Navbar extends Component{
224
  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>
225
 
226
  <div className=" absolute -mt-2 text-4xl opacity-60 z-10 ">{`${this.state.emoji[index] === null ? "" : this.state.emoji[index]}`}</div>
227
- <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={{"text-shadow" : "0px 1px 2px rgba(0, 0, 0, 0.25)"}} >{`${item.name}`} </h4>
228
 
229
  </li >
230
 
@@ -260,7 +257,7 @@ export default class Navbar extends Component{
260
  Append Shared Gradio Hosts
261
  </Header>
262
  <Modal.Content>
263
- <div className=" text-center select-none">Host other HugginFace Models or Gradio application via shared lin</div>
264
  <div className={`flex items-center rounded-md bg-light-white mt-6 border-dashed`}>
265
  <label className="relative block w-full">
266
  <span className={`absolute inset-y-0 left-0 flex items-center pl-3`}>
 
8
  export default class Navbar extends Component{
9
  constructor(props){
10
  super(props)
 
11
  this.temp_host = 0
12
  this.deleteNode = props.onDelete
13
  this.state = {open : true,
14
  menu : [],
15
+ colour : props.colour,
16
  text : "",
17
  name : "",
18
+ emoji : props.emoji,
19
  mode : false,
20
  modal : false,
21
  error : false
22
  }
23
+ this.fetch_classes()
24
  }
25
 
26
 
 
79
  }
80
 
81
  fetch(this.state.text, {method : "GET", mode: 'no-cors'}).then((re) => {
82
+ //console.log(re)
83
  fetch("http://localhost:2000/api/append/port", {method: 'POST', mode : 'cors', headers : { 'Content-Type' : 'application/json' }, body: JSON.stringify({file : "", kwargs : {}, name : this.state.name === "" ?`temp_class_${this.temp_host++}` : `${this.state.name}`, port: 0 , host : this.state.text}) }).then(resp => {
84
  this.setState({open : this.state.open,
85
  menu : this.state.menu,
 
99
  error : true,
100
  modal : this.state.modal }))
101
  }).catch((err)=>{
102
+ //console.log(err)
103
  this.setState({open : this.state.open,
104
  menu : this.state.menu,
105
  text: '',
 
135
  */
136
  onDragStart = (event, nodeType, item, index) => {
137
  event.dataTransfer.setData('application/reactflow', nodeType);
138
+ event.dataTransfer.setData('application/style', JSON.stringify({colour : this.state.colour[index], emoji : this.state.emoji[index] }))
139
  event.dataTransfer.setData('application/item', JSON.stringify(item))
140
  event.dataTransfer.effectAllowed = 'move';
141
  };
 
161
  * @param {*} d integer variable of the diffence between the current menu and new menu updated ment
162
  */
163
  hanelTabs = (e, d) => {
164
+ if (e.length === this.state.colour.length){
165
+ this.setState({open : this.state.open, menu : e, text: this.state.text, name: this.state.name, colour : this.state.colour, emoji : this.state.emoji, error : this.state.error, modal : this.state.modal })
166
+ return
167
+ }
168
  // if less then 0 we must remove colour's and emoji's
169
  // get index of the object
170
  // remove
 
181
  this.setState({open : this.state.open, menu : e, text: this.state.text, name: this.state.name, colour : c, emoji : j, error : this.state.error, modal : this.state.modal })
182
  }else{
183
  //append new colours
184
+
185
  for(var i =0; i < d; i++){
186
  c.push(random_colour(i === 0 ? null : c[i-1]));
187
  j.push(random_emoji(i === 0 ? null : c[i-1]));
 
191
  }
192
  }
193
 
 
 
 
 
 
 
 
194
  /**
195
  * handel navagation open and close function
196
  */
 
221
  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>
222
 
223
  <div className=" absolute -mt-2 text-4xl opacity-60 z-10 ">{`${this.state.emoji[index] === null ? "" : this.state.emoji[index]}`}</div>
224
+ <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>
225
 
226
  </li >
227
 
 
257
  Append Shared Gradio Hosts
258
  </Header>
259
  <Modal.Content>
260
+ <div className=" text-center select-none">Host other HugginFace Models or Gradio application via shared link</div>
261
  <div className={`flex items-center rounded-md bg-light-white mt-6 border-dashed`}>
262
  <label className="relative block w-full">
263
  <span className={`absolute inset-y-0 left-0 flex items-center pl-3`}>
frontend/src/components/Nodes/Custom.js CHANGED
@@ -37,7 +37,6 @@ export default class CustomNodeIframe extends React.Component {
37
  fetch(host, {mode: 'no-cors'}).then((re) => {
38
  return true
39
  }).catch((err)=>{
40
- alert(`πŸ€ͺ Something went wrong the url that that was put in is not reachable...\n\n${err}`)
41
  return false
42
  })
43
  return false
@@ -49,8 +48,9 @@ export default class CustomNodeIframe extends React.Component {
49
  }
50
 
51
  onRefresh(){
52
- if(!this.isFetchable) this.onNodeClick(this.state.id)
53
- else{
 
54
  this.setState({id : this.state.id, reachable : this.state.reachable, selected : this.state.selected, data : this.state.data, width : this.state.width, height : this.state.height, size : this.state.size, iframe : this.state.iframe + 1, initial_pos : this.state.initial_pos, initial_size : this.state.initial_size})
55
  }
56
  }
@@ -74,8 +74,9 @@ export default class CustomNodeIframe extends React.Component {
74
  }
75
 
76
  resize = (e) => {
77
- this.setState({id : this.state.id, reachable : this.state.reachable, selected : this.state.selected, data : this.state.data, width : this.state.width, height : this.state.height, size : this.state.size, iframe : this.state.iframe, initial_pos : this.state.initial_pos, initial_size : this.state.initial_size})
78
- this.myRef.current.style.height = `${parseInt(this.state.initial_size) + parseInt(e.clientY - this.state.initial_pos)}px`
 
79
  }
80
 
81
  Counter(focus, size){
@@ -93,7 +94,7 @@ export default class CustomNodeIframe extends React.Component {
93
  }
94
 
95
  render(){
96
- if (!this.state.reachable) this.onNodeClick(this.state.id)
97
  return (<>
98
  <>
99
  <div className=" flex w-full h-10 top-0 cursor-pointer" onClick={this.handelEvent}>
@@ -128,8 +129,8 @@ export default class CustomNodeIframe extends React.Component {
128
  {/* (Experimental) Do not uncomment */}
129
  <div className={`absolute bottom-0 w-full h-10 bg-transparent border-1 shadow-2xl rounded-xl z-10 cursor-ns-resize`}
130
  draggable
131
- onDragStart={(e) => { this.initial(e)}}
132
- onDrag={(e) => { this.resize(e)}}
133
  ></div>
134
  </>
135
  </>)
 
37
  fetch(host, {mode: 'no-cors'}).then((re) => {
38
  return true
39
  }).catch((err)=>{
 
40
  return false
41
  })
42
  return false
 
48
  }
49
 
50
  onRefresh(){
51
+ if(!this.isFetchable(this.state.data.host)){
52
+ this.onNodeClick(this.state.id)
53
+ } else{
54
  this.setState({id : this.state.id, reachable : this.state.reachable, selected : this.state.selected, data : this.state.data, width : this.state.width, height : this.state.height, size : this.state.size, iframe : this.state.iframe + 1, initial_pos : this.state.initial_pos, initial_size : this.state.initial_size})
55
  }
56
  }
 
74
  }
75
 
76
  resize = (e) => {
77
+ var new_height = parseInt(this.state.initial_size) + parseInt(e.clientY - this.state.initial_pos)
78
+ this.setState({id : this.state.id, reachable : this.state.reachable, selected : this.state.selected, data : this.state.data, width : this.state.width, height : new_height, size : this.state.size, iframe : this.state.iframe, initial_pos : this.state.initial_pos, initial_size : this.state.initial_size})
79
+ this.myRef.current.style.height = `${new_height}px`
80
  }
81
 
82
  Counter(focus, size){
 
94
  }
95
 
96
  render(){
97
+ if (!this.state.reachable) {this.onNodeClick(this.state.id) }
98
  return (<>
99
  <>
100
  <div className=" flex w-full h-10 top-0 cursor-pointer" onClick={this.handelEvent}>
 
129
  {/* (Experimental) Do not uncomment */}
130
  <div className={`absolute bottom-0 w-full h-10 bg-transparent border-1 shadow-2xl rounded-xl z-10 cursor-ns-resize`}
131
  draggable
132
+ onDragStart={(e) => { this.initial(e) }}
133
+ onDrag={(e) => { this.resize(e) }}
134
  ></div>
135
  </>
136
  </>)
frontend/src/components/ReactFlow/ReactFlowEnv.js CHANGED
@@ -2,10 +2,9 @@ import CustomNodeIframe from "../Nodes/Custom.js";
2
  import '../../css/dist/output.css'
3
  import ReactFlow, { Background,
4
  applyNodeChanges,
5
- applyEdgeChanges,
6
  ReactFlowProvider,
7
  } from 'react-flow-renderer';
8
- import React ,{ useState, useCallback, useRef } from 'react';
9
  import Navbar from '../Navagation/navbar';
10
  import { useThemeDetector } from '../../helper/visual'
11
 
@@ -17,20 +16,31 @@ export default function ReactEnviorment() {
17
 
18
  const [theme, setTheme] = useState(useThemeDetector)
19
  const [nodes, setNodes] = useState([]);
20
- const [edges, setEdges] = useState([]);
21
  const [reactFlowInstance, setReactFlowInstance] = useState(null);
22
  const reactFlowWrapper = useRef(null);
23
 
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  const onNodesChange = useCallback(
26
  (changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
27
  [setNodes]
28
  );
29
 
30
- const onEdgesChange = useCallback(
31
- (changes) => setEdges((eds) => applyEdgeChanges(changes, eds)),
32
- [setEdges]
33
- );
34
 
35
  const onDragOver = useCallback((event) => {
36
  event.preventDefault();
@@ -40,6 +50,25 @@ export default function ReactEnviorment() {
40
  const deleteNodeContains = (id) =>{setNodes((nds) => nds.filter(n => !n.id.includes(`${id}-`) ))}
41
  const deleteNode = (id) =>{setNodes((nds) => nds.filter(n => n.id !== id ))}
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
  const onDrop = useCallback(
45
  (event) => {
@@ -49,7 +78,7 @@ export default function ReactEnviorment() {
49
  const reactFlowBounds = reactFlowWrapper.current.getBoundingClientRect();
50
  const type = event.dataTransfer.getData('application/reactflow');
51
  const item = JSON.parse(event.dataTransfer.getData('application/item'));
52
- const colour = event.dataTransfer.getData('application/colour');
53
  // check if the dropped element is valid
54
  if (typeof type === 'undefined' || !type) {
55
  return;
@@ -59,13 +88,15 @@ export default function ReactEnviorment() {
59
  x: event.clientX - reactFlowBounds.left,
60
  y: event.clientY - reactFlowBounds.top,
61
  });
 
62
  const newNode = {
63
- id: `${item.name}-${nodes.length}`,
64
  type,
65
  position,
66
  dragHandle : `#draggable`,
67
- data: { label: `${item.name}`, host : `${item.host}`, colour : `${colour}`, delete : deleteNode },
68
  };
 
69
  setNodes((nds) => nds.concat(newNode));
70
  }
71
  },
@@ -73,14 +104,15 @@ export default function ReactEnviorment() {
73
 
74
  return (
75
  <>
76
- <div className=' absolute top-4 right-5 z-50' onClick={()=> setTheme(!theme)}>
77
- <h1 className='text-4xl select-none' >{theme ? 'πŸŒ™' : 'β˜€οΈ'}</h1>
 
78
  </div>
79
  <div className={`flex h-screen w-screen ${theme ? "dark" : ""} transition-all`}>
80
- <Navbar onDelete={deleteNodeContains}/>
81
  <ReactFlowProvider>
82
  <div className="h-screen w-screen" ref={reactFlowWrapper}>
83
- <ReactFlow nodes={nodes} edges={edges} nodeTypes={types} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onNodesDelete={deleteNode} onDragOver={onDragOver} onDrop={onDrop} onInit={setReactFlowInstance} fitView>
84
  <Background variant='dots' size={1} className=" bg-white dark:bg-neutral-800"/>
85
  </ReactFlow>
86
  </div>
 
2
  import '../../css/dist/output.css'
3
  import ReactFlow, { Background,
4
  applyNodeChanges,
 
5
  ReactFlowProvider,
6
  } from 'react-flow-renderer';
7
+ import React ,{ useState, useCallback, useRef, useEffect } from 'react';
8
  import Navbar from '../Navagation/navbar';
9
  import { useThemeDetector } from '../../helper/visual'
10
 
 
16
 
17
  const [theme, setTheme] = useState(useThemeDetector)
18
  const [nodes, setNodes] = useState([]);
 
19
  const [reactFlowInstance, setReactFlowInstance] = useState(null);
20
  const reactFlowWrapper = useRef(null);
21
 
22
 
23
+ useEffect(() => {
24
+ const restore = () => {
25
+ const flow = JSON.parse(localStorage.getItem('flowkey'));
26
+
27
+ if(flow){
28
+ flow.nodes.map((nds) => {
29
+ nds.data.delete = deleteNode
30
+ })
31
+ setNodes(flow.nodes || [])
32
+
33
+ }
34
+ }
35
+ restore()
36
+ },[])
37
+
38
+
39
  const onNodesChange = useCallback(
40
  (changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
41
  [setNodes]
42
  );
43
 
 
 
 
 
44
 
45
  const onDragOver = useCallback((event) => {
46
  event.preventDefault();
 
50
  const deleteNodeContains = (id) =>{setNodes((nds) => nds.filter(n => !n.id.includes(`${id}-`) ))}
51
  const deleteNode = (id) =>{setNodes((nds) => nds.filter(n => n.id !== id ))}
52
 
53
+ const onSave = useCallback(() => {
54
+ if (reactFlowInstance) {
55
+ alert("Saved")
56
+ const flow = reactFlowInstance.toObject();
57
+ localStorage.setItem('flowkey', JSON.stringify(flow));
58
+ var labels = [];
59
+ var colour = [];
60
+ var emoji = [];
61
+ for(let i = 0; i < flow.nodes.length; i++){
62
+ if (!labels.includes(flow.nodes[i].data.label))
63
+ colour.push(flow.nodes[i].data.colour)
64
+ emoji.push(flow.nodes[i].data.emoji)
65
+ labels.push(flow.nodes[i].data.label)
66
+ }
67
+ localStorage.setItem('colour',JSON.stringify(colour))
68
+ localStorage.setItem('emoji', JSON.stringify(emoji))
69
+ }
70
+ }, [reactFlowInstance]);
71
+
72
 
73
  const onDrop = useCallback(
74
  (event) => {
 
78
  const reactFlowBounds = reactFlowWrapper.current.getBoundingClientRect();
79
  const type = event.dataTransfer.getData('application/reactflow');
80
  const item = JSON.parse(event.dataTransfer.getData('application/item'));
81
+ const style = JSON.parse(event.dataTransfer.getData('application/style'));
82
  // check if the dropped element is valid
83
  if (typeof type === 'undefined' || !type) {
84
  return;
 
88
  x: event.clientX - reactFlowBounds.left,
89
  y: event.clientY - reactFlowBounds.top,
90
  });
91
+
92
  const newNode = {
93
+ id: `${item.name}-${nodes.length+1}`,
94
  type,
95
  position,
96
  dragHandle : `#draggable`,
97
+ data: { label: `${item.name}`, host : `${item.host}`, colour : `${style.colour}`, emoji : `${style.emoji}`, delete : deleteNode },
98
  };
99
+
100
  setNodes((nds) => nds.concat(newNode));
101
  }
102
  },
 
104
 
105
  return (
106
  <>
107
+ <div className=' absolute top-4 right-5 z-50 cursor-default select-none text-4xl ' >
108
+ <h1 title={theme ? 'Dark Mode' : 'Light Mode'} onClick={() => setTheme(!theme)} >{theme ? 'πŸŒ™' : 'β˜€οΈ'}</h1>
109
+ <h1 title="Save" className=" pt-5" onClick={() => onSave()}>πŸ’Ύ</h1>
110
  </div>
111
  <div className={`flex h-screen w-screen ${theme ? "dark" : ""} transition-all`}>
112
+ <Navbar onDelete={deleteNodeContains} colour={JSON.parse(localStorage.getItem('colour'))} emoji={JSON.parse(localStorage.getItem('emoji'))}/>
113
  <ReactFlowProvider>
114
  <div className="h-screen w-screen" ref={reactFlowWrapper}>
115
+ <ReactFlow nodes={nodes} nodeTypes={types} onNodesChange={onNodesChange} onNodesDelete={deleteNode} onDragOver={onDragOver} onDrop={onDrop} onInit={setReactFlowInstance} fitView>
116
  <Background variant='dots' size={1} className=" bg-white dark:bg-neutral-800"/>
117
  </ReactFlow>
118
  </div>
frontend/src/css/dist/output.css CHANGED
@@ -790,6 +790,10 @@ video {
790
  cursor: ns-resize;
791
  }
792
 
 
 
 
 
793
  .select-none {
794
  -webkit-user-select: none;
795
  user-select: none;
@@ -1210,6 +1214,10 @@ video {
1210
  padding-top: 0.5rem;
1211
  }
1212
 
 
 
 
 
1213
  .text-center {
1214
  text-align: center;
1215
  }
 
790
  cursor: ns-resize;
791
  }
792
 
793
+ .cursor-default {
794
+ cursor: default;
795
+ }
796
+
797
  .select-none {
798
  -webkit-user-select: none;
799
  user-select: none;
 
1214
  padding-top: 0.5rem;
1215
  }
1216
 
1217
+ .pt-5 {
1218
+ padding-top: 1.25rem;
1219
+ }
1220
+
1221
  .text-center {
1222
  text-align: center;
1223
  }