LucaVivona commited on
Commit
7f30a93
Β·
1 Parent(s): 6e075ce

refactor frontend/backend πŸ‘¨β€πŸ’»

Browse files
backend/src/resources/module.py CHANGED
@@ -1,41 +1,77 @@
 
1
  import gradio as gr
2
  from inspect import getfile
3
-
4
  import socket
5
  import requests
6
-
7
  class Dock:
8
 
9
  def __init__(self) -> None:
10
  self.port_map = dict()
11
  for p in range(7860, 7880):
12
- if not self.portConnection(p):
13
  self.port_map[p] = True
 
 
 
 
14
 
15
- def portConnection(self, port : int):
16
- s = socket.socket(
17
- socket.AF_INET, socket.SOCK_STREAM)
18
- result = s.connect_ex(("localhost", port))
19
- if result == 0: return True
20
- return False
 
 
 
 
21
 
22
- def determinePort(self):
 
 
 
 
 
 
23
  for port, available in self.port_map.items():
24
  if available == True:
 
 
25
  return port
 
26
  raise Exception(f'❌ πŸ”Œ {bcolor.BOLD}{bcolor.UNDERLINE}{bcolor.FAIL}All visable ports are used up...Try close some ports {bcolor.ENDC}')
27
 
28
- DOCKER_LOCAL_HOST = '0.0.0.0'
29
- DOCKER_PORT = Dock()
 
 
 
 
30
 
31
  def InterLauncher(name, interface, listen=2000, **kwargs):
32
- port= kwargs["port"] if "port" in kwargs else DOCKER_PORT.determinePort()
 
 
 
 
 
 
 
 
 
 
 
 
33
  try:
 
34
  requests.post(f"http://{DOCKER_LOCAL_HOST}:{listen}/api/append/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : "Not Applicable", "name" : name, "kwargs" : kwargs})
35
- except Exception as e:
 
36
  print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πŸ›The listening api is either not up or you choose the wrong port.πŸ› \n {e}")
37
  return
38
 
 
39
  interface.launch(server_port=port,
40
  server_name=f"{DOCKER_LOCAL_HOST}",
41
  inline= kwargs['inline'] if "inline" in kwargs else False,
@@ -58,6 +94,9 @@ def InterLauncher(name, interface, listen=2000, **kwargs):
58
  quiet=kwargs['quiet'] if "quiet" in kwargs else False)
59
 
60
  try:
 
 
 
61
  requests.post(f"http://{DOCKER_LOCAL_HOST}:{ listen }/api/remove/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : 'Not Applicable', "name" : name, "kwargs" : kwargs})
62
  except Exception as e:
63
  print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πŸ›The api either lost connection or was turned off...πŸ› \n {e}")
@@ -77,6 +116,7 @@ def tabularGradio(funcs, names=[], name="Tabular Temp Name", **kwargs):
77
  # send this to the backend api for it to be read by the react frontend
78
  if 'listen' in kwargs:
79
  try:
 
80
  requests.post(f"http://{DOCKER_LOCAL_HOST}:{ kwargs[ 'listen' ] }/api/append/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : 'Not Applicable', "name" : name, "kwargs" : kwargs})
81
  except Exception as e:
82
  print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πŸ›The listening api is either not up or you choose the wrong port.πŸ› \n {e}")
@@ -116,14 +156,21 @@ def tabularGradio(funcs, names=[], name="Tabular Temp Name", **kwargs):
116
 
117
 
118
  def register(inputs, outputs, examples=None, **kwargs):
 
 
 
 
 
119
  def register_gradio(func):
120
-
121
-
122
- def decorator(*args, **wargs):
123
  if type(outputs) is list:
124
  assert len(outputs) >= 1, f"❌ {bcolor.BOLD}{bcolor.FAIL}you have no outputs 🀨... {str(type(outputs))} {bcolor.ENDC}"
125
 
126
- fn_name = func.__name__
 
 
127
  if 'self' in func.__code__.co_varnames and func.__code__.co_varnames[0] == 'self' and fn_name in dir(args[0]):
128
  """
129
  given the decorator is on a class then
@@ -131,6 +178,7 @@ def register(inputs, outputs, examples=None, **kwargs):
131
  if not already initialize.
132
  """
133
 
 
134
  if type(inputs) is list:
135
  assert len(inputs) == func.__code__.co_argcount - 1, f"❌ {bcolor.BOLD}{bcolor.FAIL}inputs should have the same length as arguments{bcolor.ENDC}"
136
 
@@ -138,8 +186,9 @@ def register(inputs, outputs, examples=None, **kwargs):
138
  self = args[0]
139
  self.registered_gradio_functons
140
  except AttributeError:
141
- self.registered_gradio_functons = dict()
142
 
 
143
  if not fn_name in self.registered_gradio_functons:
144
  self.registered_gradio_functons[fn_name] = dict(inputs=inputs,
145
  outputs=outputs,
@@ -156,13 +205,19 @@ def register(inputs, outputs, examples=None, **kwargs):
156
  allow_flagging=kwargs['allow_flagging'] if "allow_flagging" in kwargs else None,
157
  theme=kwargs['theme'] if "theme" in kwargs else 'default', )
158
 
 
 
159
  if len(args[1:]) == (func.__code__.co_argcount - 1):
160
  return func(*args, **wargs)
 
 
161
  return None
162
  else :
163
  """
164
  the function is not a class function
165
  """
 
 
166
  if type(inputs) is list:
167
  assert len(inputs) == func.__code__.co_argcount, f"❌ {bcolor.BOLD}{bcolor.FAIL}inputs should have the same length as arguments{bcolor.ENDC}"
168
 
@@ -187,7 +242,7 @@ def register(inputs, outputs, examples=None, **kwargs):
187
  allow_flagging=kwargs['allow_flagging'] if "allow_flagging" in kwargs else None,
188
  theme='default',
189
  )
190
- decorator.__decorator__ = "__gradio__"
191
  return decorator
192
  return register_gradio
193
 
@@ -200,14 +255,23 @@ def GradioModule(cls):
200
  self.interface = self.__compile()
201
 
202
  def get_funcs_names(self):
 
 
 
203
  assert self.get_registered_map() != None, "this is not possible..."
204
  return [ name for name in self.get_registered_map().keys()]
205
 
206
  def get_registered_map(self):
 
 
 
207
  assert self.__cls__.registered_gradio_functons != None, "what happen!!!!"
208
  return self.__cls__.registered_gradio_functons
209
 
210
  def __get_funcs_attr(self):
 
 
 
211
  for func in dir(self.__cls__):
212
  fn = getattr(self.__cls__, func, None)
213
 
@@ -220,8 +284,8 @@ def GradioModule(cls):
220
  within the class that are registeed
221
  """
222
  demos, names = [], []
223
- for func, param in self.get_registered_map().items():
224
- names.append(func)
225
  try:
226
  demos.append(gr.Interface(fn=getattr(self.__cls__, func, None), **param))
227
  except Exception as e :
@@ -232,6 +296,13 @@ def GradioModule(cls):
232
  return gr.TabbedInterface(demos, names)
233
 
234
  def launch(self, **kwargs):
 
 
 
 
 
 
 
235
  port= kwargs["port"] if "port" in kwargs else DOCKER_PORT.determinePort()
236
  if 'listen' in kwargs:
237
  try:
@@ -269,6 +340,7 @@ def GradioModule(cls):
269
 
270
  return Decorator
271
 
 
272
  class bcolor:
273
  HEADER = '\033[95m'
274
  OKBLUE = '\033[94m'
 
1
+ from signal import signal, SIGKILL
2
  import gradio as gr
3
  from inspect import getfile
 
4
  import socket
5
  import requests
6
+ import os
7
  class Dock:
8
 
9
  def __init__(self) -> None:
10
  self.port_map = dict()
11
  for p in range(7860, 7880):
12
+ if not self.port_is_connected(p):
13
  self.port_map[p] = True
14
+ else:
15
+ self.port_map[p] = False
16
+
17
+
18
 
19
+ def port_is_connected(self, port : int) -> bool:
20
+ """
21
+ @params:
22
+ - port : int
23
+ @return:
24
+ - boolean
25
+ check if the port is open with in our localhost
26
+ """
27
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
28
+ return s.connect_ex(("localhost", port)) == 0
29
 
30
+
31
+ def determinePort(self) -> any:
32
+ """
33
+ Take the port_map that was instantiate
34
+ in the __init__ and loop though all ports
35
+ and check if it the port is available
36
+ """
37
  for port, available in self.port_map.items():
38
  if available == True:
39
+ if self.port_is_connected(port): # check if port is in use if so then go to the next one
40
+ continue
41
  return port
42
+
43
  raise Exception(f'❌ πŸ”Œ {bcolor.BOLD}{bcolor.UNDERLINE}{bcolor.FAIL}All visable ports are used up...Try close some ports {bcolor.ENDC}')
44
 
45
+
46
+
47
+
48
+
49
+ DOCKER_LOCAL_HOST = '0.0.0.0'
50
+ DOCKER_PORT = Dock() # Determine the best possible port
51
 
52
  def InterLauncher(name, interface, listen=2000, **kwargs):
53
+ """
54
+ @params:
55
+ - name : string
56
+ - interface : gradio.Interface(...)
57
+ - listen : int
58
+ - **kwargs
59
+
60
+ Take any gradio interface object
61
+ that is created by the gradio
62
+ package and send it to the flaks api
63
+ """
64
+ port= kwargs["port"] if "port" in kwargs else DOCKER_PORT.determinePort() # determine the next open port is no port is listed **kwargs
65
+
66
  try:
67
+ # (POST) send the information of the gradio to the flask api
68
  requests.post(f"http://{DOCKER_LOCAL_HOST}:{listen}/api/append/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : "Not Applicable", "name" : name, "kwargs" : kwargs})
69
+ except Exception as e:
70
+ # If there is an Exception then notify the user and end the method
71
  print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πŸ›The listening api is either not up or you choose the wrong port.πŸ› \n {e}")
72
  return
73
 
74
+ # Launch the gradio application
75
  interface.launch(server_port=port,
76
  server_name=f"{DOCKER_LOCAL_HOST}",
77
  inline= kwargs['inline'] if "inline" in kwargs else False,
 
94
  quiet=kwargs['quiet'] if "quiet" in kwargs else False)
95
 
96
  try:
97
+ # (POST) stop the interface if user hits ctrl+c
98
+ # send the information of the gradio to the flask
99
+ # api to remove it from the list within the flask api
100
  requests.post(f"http://{DOCKER_LOCAL_HOST}:{ listen }/api/remove/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : 'Not Applicable', "name" : name, "kwargs" : kwargs})
101
  except Exception as e:
102
  print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πŸ›The api either lost connection or was turned off...πŸ› \n {e}")
 
116
  # send this to the backend api for it to be read by the react frontend
117
  if 'listen' in kwargs:
118
  try:
119
+ # (POST) send the information of the gradio to the flask api
120
  requests.post(f"http://{DOCKER_LOCAL_HOST}:{ kwargs[ 'listen' ] }/api/append/port", json={"port" : port, "host" : f'http://localhost:{port}', "file" : 'Not Applicable', "name" : name, "kwargs" : kwargs})
121
  except Exception as e:
122
  print(f"**{bcolor.BOLD}{bcolor.FAIL}CONNECTION ERROR{bcolor.ENDC}** πŸ›The listening api is either not up or you choose the wrong port.πŸ› \n {e}")
 
156
 
157
 
158
  def register(inputs, outputs, examples=None, **kwargs):
159
+ """
160
+ Decorator that is appended to a function either within a class or not
161
+ and output either an interface or inputs and outputs for later processing
162
+ to launch either to Gradio-Flow or just Gradio
163
+ """
164
  def register_gradio(func):
165
+ def decorator(*args, **wargs):
166
+
167
+ # if the output is a list then there should be equal or more then 1
168
  if type(outputs) is list:
169
  assert len(outputs) >= 1, f"❌ {bcolor.BOLD}{bcolor.FAIL}you have no outputs 🀨... {str(type(outputs))} {bcolor.ENDC}"
170
 
171
+ fn_name = func.__name__ # name of the function
172
+
173
+ # if there exist the self within the arguments and thats the first argument then this must be a class function
174
  if 'self' in func.__code__.co_varnames and func.__code__.co_varnames[0] == 'self' and fn_name in dir(args[0]):
175
  """
176
  given the decorator is on a class then
 
178
  if not already initialize.
179
  """
180
 
181
+ # if the inputs is a list then inputs list should equal the arugments list
182
  if type(inputs) is list:
183
  assert len(inputs) == func.__code__.co_argcount - 1, f"❌ {bcolor.BOLD}{bcolor.FAIL}inputs should have the same length as arguments{bcolor.ENDC}"
184
 
 
186
  self = args[0]
187
  self.registered_gradio_functons
188
  except AttributeError:
189
+ self.registered_gradio_functons = dict() # if registered_gradio_functons does not exist then create it
190
 
191
+ # if the function name is not within the registered_gradio_functons then register it within the registered_gradio_functons
192
  if not fn_name in self.registered_gradio_functons:
193
  self.registered_gradio_functons[fn_name] = dict(inputs=inputs,
194
  outputs=outputs,
 
205
  allow_flagging=kwargs['allow_flagging'] if "allow_flagging" in kwargs else None,
206
  theme=kwargs['theme'] if "theme" in kwargs else 'default', )
207
 
208
+ # if the argument are within the function when it's called then give me the output of the function
209
+ # giving the user the ability to use the function if necessary
210
  if len(args[1:]) == (func.__code__.co_argcount - 1):
211
  return func(*args, **wargs)
212
+
213
+ # return nothing if the arguments are not within it cause if the arguments do not exist it will give a error
214
  return None
215
  else :
216
  """
217
  the function is not a class function
218
  """
219
+
220
+ # if the inputs is a list then inputs list should equal the arugments list
221
  if type(inputs) is list:
222
  assert len(inputs) == func.__code__.co_argcount, f"❌ {bcolor.BOLD}{bcolor.FAIL}inputs should have the same length as arguments{bcolor.ENDC}"
223
 
 
242
  allow_flagging=kwargs['allow_flagging'] if "allow_flagging" in kwargs else None,
243
  theme='default',
244
  )
245
+ decorator.__decorator__ = "__gradio__" # siginture to tell any function that need to know that function is a registed gradio application
246
  return decorator
247
  return register_gradio
248
 
 
255
  self.interface = self.__compile()
256
 
257
  def get_funcs_names(self):
258
+ """
259
+ Get all name for each function
260
+ """
261
  assert self.get_registered_map() != None, "this is not possible..."
262
  return [ name for name in self.get_registered_map().keys()]
263
 
264
  def get_registered_map(self):
265
+ """
266
+ Get all registered functions
267
+ """
268
  assert self.__cls__.registered_gradio_functons != None, "what happen!!!!"
269
  return self.__cls__.registered_gradio_functons
270
 
271
  def __get_funcs_attr(self):
272
+ """
273
+ Get all the function that are registered
274
+ """
275
  for func in dir(self.__cls__):
276
  fn = getattr(self.__cls__, func, None)
277
 
 
284
  within the class that are registeed
285
  """
286
  demos, names = [], []
287
+ for func, param in self.get_registered_map().items(): # loop though the registered function and append it to the TabularInterface
288
+ names.append(func)
289
  try:
290
  demos.append(gr.Interface(fn=getattr(self.__cls__, func, None), **param))
291
  except Exception as e :
 
296
  return gr.TabbedInterface(demos, names)
297
 
298
  def launch(self, **kwargs):
299
+ """
300
+ @params:
301
+ **kwargs
302
+ Take the tabular interface and send it to the api if
303
+ 'listen' is within the kwargs and launch the gradio interface
304
+ then when the gradio stops then remove it from the api
305
+ """
306
  port= kwargs["port"] if "port" in kwargs else DOCKER_PORT.determinePort()
307
  if 'listen' in kwargs:
308
  try:
 
340
 
341
  return Decorator
342
 
343
+ # console colour changer
344
  class bcolor:
345
  HEADER = '\033[95m'
346
  OKBLUE = '\033[94m'
frontend/src/App.js CHANGED
@@ -1,4 +1,4 @@
1
- import ReactEnviorment from './Components/ReactFlow/ReactFlowEnv'
2
 
3
  export default function App() {
4
  return(
 
1
+ import ReactEnviorment from './components/ReactFlow/ReactFlowEnv'
2
 
3
  export default function App() {
4
  return(
frontend/src/{Components β†’ components}/Navagation/navbar.js RENAMED
@@ -6,10 +6,11 @@ import { random_colour, random_emoji } from "../../helper/visual";
6
  import { Message, Header, Modal, Button, Icon } from 'semantic-ui-react'
7
 
8
  export default class Navbar extends Component{
9
- constructor(){
10
- super()
11
  this.fetch_classes()
12
  this.temp_host = 0
 
13
  this.state = {open : true,
14
  menu : [],
15
  colour : [],
@@ -19,11 +20,15 @@ export default class Navbar extends Component{
19
  mode : false,
20
  modal : false,
21
  error : false
 
22
  }
23
  }
24
 
25
 
26
-
 
 
 
27
  async fetch_classes(){
28
  try {
29
  setInterval( async () => {
@@ -47,35 +52,39 @@ export default class Navbar extends Component{
47
  }
48
  }
49
 
50
- append_gradio = () => {
51
- // var expression = /((http([s]){0,1}:\/\/){0,1}(localhost|127.0.0.1){1}(([:]){0,1}[\0-9]{4}){0,1}\/{0,1}){1}/g;
52
- // var regex = new RegExp(expression);
53
- // if(!this.state.text.match(regex) || (this.state.text === "http://localhost:3001/")){
54
- // this.setState({open : this.state.open,
55
- // menu : this.state.menu,
56
- // text: this.state.text,
57
- // name : this.state.name,
58
- // colour : this.state.colour,
59
- // emoji : this.state.emoji,
60
- // error : true,
61
- // modal : this.state.modal })
62
- // return
63
- // }
64
-
65
- // if((this.state.text.includes("localhost") || this.state.text.includes("127.0.0.1"))
66
- // && this.state.menu.some(e => e.host === this.state.text)){
67
- // this.setState({open : this.state.open,
68
- // menu : this.state.menu,
69
- // text: this.state.text,
70
- // name : this.state.name,
71
- // colour : this.state.colour,
72
- // emoji : this.state.emoji,
73
- // error : true,
74
- // modal : this.state.modal })
75
 
76
- // return
 
 
 
 
77
 
78
- // }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  fetch(this.state.text, {method : "GET", mode: 'no-cors'}).then((re) => {
80
  console.log(re)
81
  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 => {
@@ -88,16 +97,31 @@ export default class Navbar extends Component{
88
  error : false,
89
  modal : false })
90
 
91
- }).catch(() => this.setState({open : this.state.open,
92
  menu : this.state.menu,
93
- text: this.state.text,
 
94
  colour : this.state.colour,
95
  emoji : this.state.emoji,
96
  error : true,
97
  modal : this.state.modal }))
 
 
 
 
 
 
 
 
 
 
98
  })
99
  }
100
 
 
 
 
 
101
  handelModal = (bool) => {
102
  this.setState({open : this.state.open,
103
  menu : this.state.menu,
@@ -109,25 +133,40 @@ export default class Navbar extends Component{
109
  modal : bool})
110
  }
111
 
112
-
 
 
 
 
 
 
113
  onDragStart = (event, nodeType, item, index) => {
114
- console.log(item)
115
  event.dataTransfer.setData('application/reactflow', nodeType);
116
- event.dataTransfer.setData('application/host', item.host)
117
- event.dataTransfer.setData('application/name', item.name)
118
  event.dataTransfer.setData('application/colour', this.state.colour[index])
119
  event.dataTransfer.setData('application/item', JSON.stringify(item))
120
-
121
  event.dataTransfer.effectAllowed = 'move';
122
  };
123
 
 
 
 
 
 
 
124
  onDragDrop = (e) => {
125
  e.preventDefault();
126
  var item = JSON.parse(e.dataTransfer.getData('application/item'));
127
  fetch("http://localhost:2000/api/remove/port", {method : "POST", mode: 'cors', headers : { 'Content-Type' : 'application/json' }, body: JSON.stringify(item) }).then((re)=>{
 
128
  })
 
129
  }
130
 
 
 
 
 
 
131
  hanelTabs = (e, d) => {
132
 
133
  // if less then 0 we must remove colour's and emoji's
@@ -150,22 +189,39 @@ export default class Navbar extends Component{
150
  c.push(random_colour());
151
  j.push(random_emoji());
152
  }
153
- this.setState({open : this.state.open, menu : e, text: this.state.text, name: this.state.name, colour : this.state.colour.concat(c), emoji : this.state.emoji.concat(j), error : this.state.error, modal : this.state.modal })
154
  }
155
  }
156
 
 
 
 
157
  appendTabs = () => {
158
  this.setState({open : this.state.open, menu : this.state.menu, text: this.state.text, name: this.state.name, colour : [...this.state.colour, random_colour] , emoji : [...this.state.emoji, random_emoji], error : this.state.error, modal : this.state.modal })
159
  }
160
 
 
 
 
161
  handelNavbar = () => {
162
  this.setState({open : !this.state.open, menu : this.state.menu, text: this.state.text, name: this.state.name, colour : this.state.colour, emoji : this.state.emoji, error : this.state.error, modal : this.state.modal })
163
  }
164
 
 
 
 
 
 
165
  updateText(e, type){
166
  this.setState({open : this.state.open, menu : this.state.menu, text: type === "text" ? e.target.value : this.state.text, name: type === "name" ? e.target.value : this.state.name, colour : this.state.colour, emoji : this.state.emoji, error : this.state.error, modal : this.state.modal })
167
  }
168
 
 
 
 
 
 
 
169
  subComponents(item, index){
170
 
171
  return(<>
@@ -213,7 +269,7 @@ export default class Navbar extends Component{
213
  <span className={`absolute inset-y-0 left-0 flex items-center pl-3`}>
214
  <BsSearch className="block float-left cursor-pointer mr-2"/>
215
  </span>
216
- <input className={`placeholder:italic placeholder:text-slate-400 block bg-transparent w-full border border-slate-300 border-dashed rounded-md py-2 pl-9 ${this.state.open ? "pr-3" : "hidden"} shadow-sm focus:outline-none focus:border-sky-500 focus:ring-sky-500 focus:ring-1 sm:text-sm`}
217
  placeholder={`stream link...`}
218
  type="text" name="search"
219
  onChange={(e) => {
@@ -240,8 +296,22 @@ export default class Navbar extends Component{
240
 
241
  { this.state.error &&
242
  <Message negative>
243
- <Message.Header>🚫 Connection to url</Message.Header>
244
- <p>πŸ€” Either the connection is forbidden, already exist within the menu or it is unreachable... </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  </Message>
246
  }
247
 
 
6
  import { Message, Header, Modal, Button, Icon } from 'semantic-ui-react'
7
 
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 : [],
 
20
  mode : false,
21
  modal : false,
22
  error : false
23
+
24
  }
25
  }
26
 
27
 
28
+ /**
29
+ * Asynchronously call the Flask api server every second to check if there exist a gradio application info
30
+ * @return null
31
+ */
32
  async fetch_classes(){
33
  try {
34
  setInterval( async () => {
 
52
  }
53
  }
54
 
55
+ /**
56
+ * Append new node from the user
57
+ */
58
+ append_gradio = async () => {
59
+ const pattern = {
60
+ local : /^https?:\/\/(localhost)*(:[0-9]+)?(\/)?$/,
61
+ share : /^https?:\/\/*([0-9]{5})*(-gradio)*(.app)?(\/)?$/,
62
+ hugginFace : /^https?:\/\/*(hf.space)\/*(embed)\/*([a-zA-Z0-9+_-]+)\/*([a-zA-Z0-9+_-]+)\/*([+])?(\/)?$/
63
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
+ if (this.state.menu.findIndex(element => {return element.name.toLowerCase() === this.state.name.toLowerCase() || element.host.includes(this.state.host) }) !== -1 ||
66
+ this.state.text.includes(" ") ||
67
+ (!pattern.local.test(this.state.text) &&
68
+ !pattern.share.test(this.state.text) &&
69
+ !pattern.hugginFace.test(this.state.text))){
70
 
71
+ console.log(this.state.menu.findIndex(element => {return element.name.toLowerCase() === this.state.name.toLowerCase() || element.host.includes(this.state.host) }) !== -1)
72
+ console.log(this.state.text.includes(" ") )
73
+ console.log(this.state.text.includes("") )
74
+ console.log(!pattern.local.test(this.state.text) &&
75
+ !pattern.share.test(this.state.text) &&
76
+ !pattern.hugginFace.test(this.state.text))
77
+ this.setState({open : this.state.open,
78
+ menu : this.state.menu,
79
+ text: '',
80
+ name : '',
81
+ colour : this.state.colour,
82
+ emoji : this.state.emoji,
83
+ error : true,
84
+ modal : this.state.modal })
85
+ return
86
+ }
87
+
88
  fetch(this.state.text, {method : "GET", mode: 'no-cors'}).then((re) => {
89
  console.log(re)
90
  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 => {
 
97
  error : false,
98
  modal : false })
99
 
100
+ }).catch((err) => this.setState({open : this.state.open,
101
  menu : this.state.menu,
102
+ text: '',
103
+ name : '',
104
  colour : this.state.colour,
105
  emoji : this.state.emoji,
106
  error : true,
107
  modal : this.state.modal }))
108
+ }).catch((err)=>{
109
+ console.log(err)
110
+ this.setState({open : this.state.open,
111
+ menu : this.state.menu,
112
+ text: '',
113
+ name : '',
114
+ colour : this.state.colour,
115
+ emoji : this.state.emoji,
116
+ error : true,
117
+ modal : this.state.modal })
118
  })
119
  }
120
 
121
+ /**
122
+ * error check the user input
123
+ * @param {*} bool boolean of the current state of the modal
124
+ */
125
  handelModal = (bool) => {
126
  this.setState({open : this.state.open,
127
  menu : this.state.menu,
 
133
  modal : bool})
134
  }
135
 
136
+ /**
137
+ * when dragged get all the information needed
138
+ * @param {*} event
139
+ * @param {*} nodeType string 'custom' node type
140
+ * @param {*} item object information returned from the api
141
+ * @param {*} index current index
142
+ */
143
  onDragStart = (event, nodeType, item, index) => {
 
144
  event.dataTransfer.setData('application/reactflow', nodeType);
 
 
145
  event.dataTransfer.setData('application/colour', this.state.colour[index])
146
  event.dataTransfer.setData('application/item', JSON.stringify(item))
 
147
  event.dataTransfer.effectAllowed = 'move';
148
  };
149
 
150
+ /**
151
+ * droped event that occurs when the user drops the Tab within the tash div.
152
+ * The function just deletes all nodes within React-Flow enviorment related,
153
+ * and remove it from the api.
154
+ * @param {*} e drop event
155
+ */
156
  onDragDrop = (e) => {
157
  e.preventDefault();
158
  var item = JSON.parse(e.dataTransfer.getData('application/item'));
159
  fetch("http://localhost:2000/api/remove/port", {method : "POST", mode: 'cors', headers : { 'Content-Type' : 'application/json' }, body: JSON.stringify(item) }).then((re)=>{
160
+ this.deleteNode(item.name)
161
  })
162
+
163
  }
164
 
165
+ /**
166
+ * update the tabs within the navbar
167
+ * @param {*} e current menu
168
+ * @param {*} d integer variable of the diffence between the current menu and new menu updated ment
169
+ */
170
  hanelTabs = (e, d) => {
171
 
172
  // if less then 0 we must remove colour's and emoji's
 
189
  c.push(random_colour());
190
  j.push(random_emoji());
191
  }
192
+ this.setState({open : this.state.open, menu : e, text: this.state.text, name: this.state.name, colour : [...this.state.colour, ...c], emoji : [...this.state.emoji, ...j], error : this.state.error, modal : this.state.modal })
193
  }
194
  }
195
 
196
+ /**
197
+ * Append a new colour, and emoji to the colour and emoji list with in the state of the component
198
+ */
199
  appendTabs = () => {
200
  this.setState({open : this.state.open, menu : this.state.menu, text: this.state.text, name: this.state.name, colour : [...this.state.colour, random_colour] , emoji : [...this.state.emoji, random_emoji], error : this.state.error, modal : this.state.modal })
201
  }
202
 
203
+ /**
204
+ * handel navagation open and close function
205
+ */
206
  handelNavbar = () => {
207
  this.setState({open : !this.state.open, menu : this.state.menu, text: this.state.text, name: this.state.name, colour : this.state.colour, emoji : this.state.emoji, error : this.state.error, modal : this.state.modal })
208
  }
209
 
210
+ /**
211
+ *
212
+ * @param {*} e : event type to get the target value of the current input
213
+ * @param {*} type : text | name string that set the changed value of the input to the current value
214
+ */
215
  updateText(e, type){
216
  this.setState({open : this.state.open, menu : this.state.menu, text: type === "text" ? e.target.value : this.state.text, name: type === "name" ? e.target.value : this.state.name, colour : this.state.colour, emoji : this.state.emoji, error : this.state.error, modal : this.state.modal })
217
  }
218
 
219
+ /**
220
+ *
221
+ * @param {*} item : object infomation from the flask api
222
+ * @param {*} index : current index with in the list
223
+ * @returns div component that contians infomation of gradio
224
+ */
225
  subComponents(item, index){
226
 
227
  return(<>
 
269
  <span className={`absolute inset-y-0 left-0 flex items-center pl-3`}>
270
  <BsSearch className="block float-left cursor-pointer mr-2"/>
271
  </span>
272
+ <input className={`placeholder:italic placeholder:text-slate-400 block bg-transparent w-full border border-slate-300 border-dashed rounded-md py-2 pl-9 ${this.state.open ? "pr-3" : "hidden"} shadow-sm focus:outline-none focus:border-sky-500 focus:ring-sky-500 focus:ring-1 sm:text-sm bg-transparent`}
273
  placeholder={`stream link...`}
274
  type="text" name="search"
275
  onChange={(e) => {
 
296
 
297
  { this.state.error &&
298
  <Message negative>
299
+ <Message.Header className=" text-lg text-center">🚫 Something went wrong...</Message.Header>
300
+ <br/>
301
+ <h1 className=" underline pb-3 font-bold text-lg">πŸ€” Possible Things That could of happen <br/></h1>
302
+ <ul className="font-bold">
303
+ <li>- The input was empty</li>
304
+ <li>- The connection was forbidden</li>
305
+ <li>- The name was already taken</li>
306
+ <li>- The link you gave did not pass the regex</li>
307
+ <ul className="px-6">
308
+ <li>- http://localhost:xxxx</li>
309
+ <li>- http://xxxxx.gradio.app</li>
310
+ <li>- https://hf.space/embed/$user/$space_name/+</li>
311
+ </ul>
312
+ <li>- link already exist within the menu</li>
313
+ </ul>
314
+
315
  </Message>
316
  }
317
 
frontend/src/{Components β†’ components}/Nodes/Custom.js RENAMED
@@ -1,6 +1,6 @@
1
  import React from "react"
2
  import {TbResize} from 'react-icons/tb'
3
- import {BiCube} from 'react-icons/bi'
4
  import {BsTrash} from 'react-icons/bs'
5
  import {CgLayoutGridSmall} from 'react-icons/cg'
6
  import '../../css/counter.css'
@@ -14,19 +14,20 @@ export default class CustomNodeIframe extends React.Component {
14
  reachable : this.isFetchable(data.host),
15
  selected : true,
16
  data : data,
17
- width : 600,
18
- height : 540,
19
- size : false
 
20
  }
21
 
22
  }
23
 
24
  handelSelected = () => {
25
- 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})
26
  }
27
 
28
  handelSizeState = () => {
29
- 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})
30
  }
31
 
32
  isFetchable = async (host) => {
@@ -45,14 +46,21 @@ export default class CustomNodeIframe extends React.Component {
45
  this.state.data.delete(id)
46
  }
47
 
 
 
 
 
 
 
 
48
  handelOnChange(evt, type){
49
- this.setState({id : this.state.id, reachable : this.state.reachable, selected : this.state.selected, data : this.state.data, width : type === "width" ? parseInt(evt.target.value) : this.state.width, height : type === "height" ? parseInt(evt.target.value) : this.state.height, size : this.state.size})
50
  type === "width" ? this.myRef.current.style.width = `${parseInt(evt.target.value)}px` : this.myRef.current.style.height = `${parseInt(evt.target.value)}px`
51
  }
52
 
53
  handelSize(evt, increment, change){
54
  if (evt === "increment") {
55
- this.setState({id : this.state.id, reachable : this.state.reachable, selected : this.state.selected, data : this.state.data, width : change === "width" ? this.state.width + increment : this.state.width, height : change === "height" ? this.state.height + increment : this.state.height, size : this.state.size})
56
  change === "width" ? this.myRef.current.style.width = `${this.state.width + increment}px` : this.myRef.current.style.height = `${this.state.height + increment}px`
57
  }
58
 
@@ -77,15 +85,16 @@ export default class CustomNodeIframe extends React.Component {
77
  return (<>
78
  <>
79
  <div className=" flex w-full h-10 top-0 cursor-pointer" onClick={this.handelEvent}>
80
- <div title="Collaspse Node" className=" duration-300 cursor-pointer shadow-xl border-2 dark:border-white border-black h-10 w-10 mr-2 -mt-3 bg-Warm-Blue rounded-xl" onClick={this.handelSelected}><CgLayoutGridSmall className="h-full w-full text-white p-1"/></div>
81
 
82
 
83
  <div className={` flex ${this.state.selected ? '' : 'w-0 hidden'}`}>
84
  <div title="Adjust Node Size" className="duration-300 cursor-pointer shadow-xl border-2 dark:border-white border-white h-10 w-10 mr-2 -mt-3 bg-Warm-Violet rounded-xl" onClick={this.handelSizeState}><TbResize className="h-full w-full text-white p-1"/></div>
85
  <a href={this.state.data.host} target="_blank" rel="noopener noreferrer"><div title="Gradio Host Site" className="duration-300 cursor-pointer shadow-xl border-2 dark:border-white border-white h-10 w-10 mr-2 -mt-3 bg-Warm-Pink rounded-xl"><BiCube className="h-full w-full text-white p-1"/></div></a>
86
  <div title="Delete Node" className="duration-300 cursor-pointer shadow-xl border-2 dark:border-white border-white h-10 w-10 mr-2 -mt-3 bg-Warm-Red rounded-xl" onClick={() => this.onNodeClick(this.state.id)}><BsTrash className="h-full w-full text-white p-1"/></div>
87
-
88
- { this.state.size && <div className="duration-300 flex w-[60%] h-full mr-2 -mt-3 space-x-4">
 
89
  {this.Counter("width", this.state.width)}
90
  {this.Counter("height", this.state.height)}
91
  </div>}
@@ -97,11 +106,11 @@ export default class CustomNodeIframe extends React.Component {
97
  <div className={`absolute h-full w-full ${this.state.data.colour} border-1shadow-2xl shadow-black rounded-xl -z-20`}></div>
98
  <iframe
99
  id="iframe"
 
100
  src={this.state.data.host}
101
  title={this.state.data.label}
102
  frameBorder="0"
103
  className=" -z-10 container h-full p-2 flex-grow space-iframe overflow-scroll "
104
- allow="accelerometer; ambient-light-sensor; autoplay; battery; camera; document-domain; encrypted-media; fullscreen; geolocation; gyroscope; layout-animations; legacy-image-formats; magnetometer; microphone; midi; oversized-images; payment; picture-in-picture; publickey-credentials-get; sync-xhr; usb; vr ; wake-lock; xr-spatial-tracking"
105
  sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>
106
  </div>
107
  </>
 
1
  import React from "react"
2
  import {TbResize} from 'react-icons/tb'
3
+ import {BiCube, BiRefresh} from 'react-icons/bi'
4
  import {BsTrash} from 'react-icons/bs'
5
  import {CgLayoutGridSmall} from 'react-icons/cg'
6
  import '../../css/counter.css'
 
14
  reachable : this.isFetchable(data.host),
15
  selected : true,
16
  data : data,
17
+ width : 540,
18
+ height : 600,
19
+ size : false,
20
+ iframe : 0
21
  }
22
 
23
  }
24
 
25
  handelSelected = () => {
26
+ 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})
27
  }
28
 
29
  handelSizeState = () => {
30
+ 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})
31
  }
32
 
33
  isFetchable = async (host) => {
 
46
  this.state.data.delete(id)
47
  }
48
 
49
+ onRefresh(){
50
+ if(!this.isFetchable) this.onNodeClick(this.state.id)
51
+ else{
52
+ 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})
53
+ }
54
+ }
55
+
56
  handelOnChange(evt, type){
57
+ this.setState({id : this.state.id, reachable : this.state.reachable, selected : this.state.selected, data : this.state.data, width : type === "width" ? parseInt(evt.target.value) : this.state.width, height : type === "height" ? parseInt(evt.target.value) : this.state.height, size : this.state.size, iframe : this.state.iframe})
58
  type === "width" ? this.myRef.current.style.width = `${parseInt(evt.target.value)}px` : this.myRef.current.style.height = `${parseInt(evt.target.value)}px`
59
  }
60
 
61
  handelSize(evt, increment, change){
62
  if (evt === "increment") {
63
+ this.setState({id : this.state.id, reachable : this.state.reachable, selected : this.state.selected, data : this.state.data, width : change === "width" ? this.state.width + increment : this.state.width, height : change === "height" ? this.state.height + increment : this.state.height, size : this.state.size, iframe : this.state.iframe})
64
  change === "width" ? this.myRef.current.style.width = `${this.state.width + increment}px` : this.myRef.current.style.height = `${this.state.height + increment}px`
65
  }
66
 
 
85
  return (<>
86
  <>
87
  <div className=" flex w-full h-10 top-0 cursor-pointer" onClick={this.handelEvent}>
88
+ <div title="Collaspse Node" className=" duration-300 cursor-pointer shadow-xl border-2 border-white h-10 w-10 mr-2 -mt-3 bg-Warm-Blue rounded-xl" onClick={this.handelSelected}><CgLayoutGridSmall className="h-full w-full text-white p-1"/></div>
89
 
90
 
91
  <div className={` flex ${this.state.selected ? '' : 'w-0 hidden'}`}>
92
  <div title="Adjust Node Size" className="duration-300 cursor-pointer shadow-xl border-2 dark:border-white border-white h-10 w-10 mr-2 -mt-3 bg-Warm-Violet rounded-xl" onClick={this.handelSizeState}><TbResize className="h-full w-full text-white p-1"/></div>
93
  <a href={this.state.data.host} target="_blank" rel="noopener noreferrer"><div title="Gradio Host Site" className="duration-300 cursor-pointer shadow-xl border-2 dark:border-white border-white h-10 w-10 mr-2 -mt-3 bg-Warm-Pink rounded-xl"><BiCube className="h-full w-full text-white p-1"/></div></a>
94
  <div title="Delete Node" className="duration-300 cursor-pointer shadow-xl border-2 dark:border-white border-white h-10 w-10 mr-2 -mt-3 bg-Warm-Red rounded-xl" onClick={() => this.onNodeClick(this.state.id)}><BsTrash className="h-full w-full text-white p-1"/></div>
95
+ <div title="Refresh Node" className="duration-300 cursor-pointer shadow-xl border-2 dark:border-white border-white h-10 w-10 mr-2 -mt-3 bg-Warm-Orange rounded-xl" onClick={() => this.onRefresh()}><BiRefresh className="h-full w-full text-white p-1"/></div>
96
+
97
+ { this.state.size && <div className="duration-300 flex w-auto h-full mr-2 -mt-3 space-x-4">
98
  {this.Counter("width", this.state.width)}
99
  {this.Counter("height", this.state.height)}
100
  </div>}
 
106
  <div className={`absolute h-full w-full ${this.state.data.colour} border-1shadow-2xl shadow-black rounded-xl -z-20`}></div>
107
  <iframe
108
  id="iframe"
109
+ key={this.state.iframe}
110
  src={this.state.data.host}
111
  title={this.state.data.label}
112
  frameBorder="0"
113
  className=" -z-10 container h-full p-2 flex-grow space-iframe overflow-scroll "
 
114
  sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"></iframe>
115
  </div>
116
  </>
frontend/src/{Components β†’ components}/ReactFlow/ReactFlowEnv.js RENAMED
@@ -1,6 +1,5 @@
1
  import CustomNodeIframe from "../Nodes/Custom.js";
2
  import '../../css/dist/output.css'
3
- import '../../css/CustomNode.css'
4
  import ReactFlow, { Background,
5
  applyNodeChanges,
6
  applyEdgeChanges,
@@ -16,14 +15,13 @@ const types = {
16
 
17
  export default function ReactEnviorment() {
18
 
19
- const [theme, setTheme] = useState(useThemeDetector())
20
  const [nodes, setNodes] = useState([]);
21
  const [edges, setEdges] = useState([]);
22
  const [reactFlowInstance, setReactFlowInstance] = useState(null);
23
  const reactFlowWrapper = useRef(null);
24
 
25
 
26
-
27
  const onNodesChange = useCallback(
28
  (changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
29
  [setNodes]
@@ -40,7 +38,7 @@ export default function ReactEnviorment() {
40
  }, []);
41
 
42
  const deleteNode = (id) =>{setNodes((nds) => nds.filter(n => n.id !== id ))}
43
-
44
  const onDrop = useCallback(
45
  (event) => {
46
  event.preventDefault();
@@ -74,7 +72,7 @@ export default function ReactEnviorment() {
74
  <h1 className='text-4xl select-none' >{theme ? 'πŸŒ™' : 'β˜€οΈ'}</h1>
75
  </div>
76
  <div className={`flex h-screen w-screen ${theme ? "dark" : ""} transition-all`}>
77
- <Navbar/>
78
  <ReactFlowProvider>
79
  <div className="h-screen w-screen" ref={reactFlowWrapper}>
80
  <ReactFlow nodes={nodes} edges={edges} nodeTypes={types} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onNodesDelete={deleteNode} onDragOver={onDragOver} onDrop={onDrop} onInit={setReactFlowInstance} fitView>
 
1
  import CustomNodeIframe from "../Nodes/Custom.js";
2
  import '../../css/dist/output.css'
 
3
  import ReactFlow, { Background,
4
  applyNodeChanges,
5
  applyEdgeChanges,
 
15
 
16
  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]
 
38
  }, []);
39
 
40
  const deleteNode = (id) =>{setNodes((nds) => nds.filter(n => n.id !== id ))}
41
+ const deleteNodeContains = (id) =>{setNodes((nds) => nds.filter(n => !n.id.includes(`${id}-`) ))}
42
  const onDrop = useCallback(
43
  (event) => {
44
  event.preventDefault();
 
72
  <h1 className='text-4xl select-none' >{theme ? 'πŸŒ™' : 'β˜€οΈ'}</h1>
73
  </div>
74
  <div className={`flex h-screen w-screen ${theme ? "dark" : ""} transition-all`}>
75
+ <Navbar onDelete={deleteNodeContains}/>
76
  <ReactFlowProvider>
77
  <div className="h-screen w-screen" ref={reactFlowWrapper}>
78
  <ReactFlow nodes={nodes} edges={edges} nodeTypes={types} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onNodesDelete={deleteNode} onDragOver={onDragOver} onDrop={onDrop} onInit={setReactFlowInstance} fitView>
frontend/src/css/CustomNode.css DELETED
@@ -1,46 +0,0 @@
1
- .hexagon {
2
- position: relative;
3
- width: 200px;
4
- height: 115.47px;
5
- background-color: #ffffff;
6
- margin: 57.74px 0;
7
- border-left: solid 3px #000000;
8
- border-right: solid 3px #000000;
9
- margin-left: auto;
10
- margin-right: auto;
11
- border-image-slice: 1;
12
- border-image-source: linear-gradient(to left, #2de2e6, #f6019d);
13
- }
14
-
15
-
16
- .hexagon:before,
17
- .hexagon:after {
18
- content: "";
19
- position: absolute;
20
- z-index: -1;
21
- width: 141.42px;
22
- height: 141.42px;
23
- -webkit-transform: scaleY(0.5774) rotate(-30deg);
24
- -ms-transform: scaleY(0.5774) rotate(-30deg);
25
- transform: scaleY(0.5774) rotate(-45deg);
26
- background-color: inherit;
27
- left: 27.2893px;
28
- }
29
-
30
- .hexagon:before {
31
- top: -70.7107px;
32
- border-top: solid 4.8284px #000000;
33
- border-right: solid 4.8284px #000000;
34
- border-image-slice: 1;
35
- border-image-source: linear-gradient(to left, #2de2e6, #f6019d);
36
-
37
- }
38
-
39
- .hexagon:after {
40
- bottom: -70.7107px;
41
- border-bottom: solid 4.8284px #000000;
42
- border-left: solid 4.8284px;
43
- border-image-slice: 1;
44
- border-image-source: linear-gradient(to left, #2de2e6, #f6019d);
45
-
46
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/src/css/dist/output.css CHANGED
@@ -744,22 +744,18 @@ video {
744
  width: 0px;
745
  }
746
 
747
- .w-\[60\%\] {
748
- width: 60%;
749
- }
750
-
751
- .w-screen {
752
- width: 100vw;
753
- }
754
-
755
- .w-\[560px\] {
756
- width: 560px;
757
  }
758
 
759
  .w-\[540px\] {
760
  width: 540px;
761
  }
762
 
 
 
 
 
763
  .flex-1 {
764
  flex: 1 1 0%;
765
  }
@@ -928,6 +924,11 @@ video {
928
  background-color: rgb(255 96 93 / var(--tw-bg-opacity));
929
  }
930
 
 
 
 
 
 
931
  .bg-gradient-to-bl {
932
  background-image: linear-gradient(to bottom left, var(--tw-gradient-stops));
933
  }
@@ -992,6 +993,30 @@ video {
992
  --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
993
  }
994
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
995
  .via-purple-500 {
996
  --tw-gradient-to: rgb(168 85 247 / 0);
997
  --tw-gradient-stops: var(--tw-gradient-from), #a855f7, var(--tw-gradient-to);
@@ -1017,11 +1042,6 @@ video {
1017
  --tw-gradient-stops: var(--tw-gradient-from), #F1A089, var(--tw-gradient-to);
1018
  }
1019
 
1020
- .via-Happy-Light-Magenta {
1021
- --tw-gradient-to: rgb(207 123 198 / 0);
1022
- --tw-gradient-stops: var(--tw-gradient-from), #CF7BC6, var(--tw-gradient-to);
1023
- }
1024
-
1025
  .via-Happy-Indego-Purple {
1026
  --tw-gradient-to: rgb(148 98 233 / 0);
1027
  --tw-gradient-stops: var(--tw-gradient-from), #9462E9, var(--tw-gradient-to);
@@ -1073,6 +1093,22 @@ video {
1073
  --tw-gradient-to: #319B72;
1074
  }
1075
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1076
  .p-5 {
1077
  padding: 1.25rem;
1078
  }
@@ -1113,6 +1149,11 @@ video {
1113
  padding-bottom: 0.5rem;
1114
  }
1115
 
 
 
 
 
 
1116
  .pt-8 {
1117
  padding-top: 2rem;
1118
  }
@@ -1141,6 +1182,10 @@ video {
1141
  padding-top: 0.5rem;
1142
  }
1143
 
 
 
 
 
1144
  .text-left {
1145
  text-align: left;
1146
  }
@@ -1200,6 +1245,11 @@ video {
1200
  color: rgb(0 0 0 / var(--tw-text-opacity));
1201
  }
1202
 
 
 
 
 
 
1203
  .shadow-lg {
1204
  --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
1205
  --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
@@ -1271,6 +1321,14 @@ video {
1271
  color: rgb(148 163 184 / var(--tw-text-opacity));
1272
  }
1273
 
 
 
 
 
 
 
 
 
1274
  @-webkit-keyframes pulse {
1275
  50% {
1276
  opacity: .5;
 
744
  width: 0px;
745
  }
746
 
747
+ .w-auto {
748
+ width: auto;
 
 
 
 
 
 
 
 
749
  }
750
 
751
  .w-\[540px\] {
752
  width: 540px;
753
  }
754
 
755
+ .w-screen {
756
+ width: 100vw;
757
+ }
758
+
759
  .flex-1 {
760
  flex: 1 1 0%;
761
  }
 
924
  background-color: rgb(255 96 93 / var(--tw-bg-opacity));
925
  }
926
 
927
+ .bg-Warm-Orange {
928
+ --tw-bg-opacity: 1;
929
+ background-color: rgb(254 169 89 / var(--tw-bg-opacity));
930
+ }
931
+
932
  .bg-gradient-to-bl {
933
  background-image: linear-gradient(to bottom left, var(--tw-gradient-stops));
934
  }
 
993
  --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
994
  }
995
 
996
+ .from-Amethyst-Light {
997
+ --tw-gradient-from: #9D50BB;
998
+ --tw-gradient-to: rgb(157 80 187 / 0);
999
+ --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
1000
+ }
1001
+
1002
+ .from-Peach-Red {
1003
+ --tw-gradient-from: #ED4264;
1004
+ --tw-gradient-to: rgb(237 66 100 / 0);
1005
+ --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
1006
+ }
1007
+
1008
+ .from-Deep-Space-Black {
1009
+ --tw-gradient-from: #000000;
1010
+ --tw-gradient-to: rgb(0 0 0 / 0);
1011
+ --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
1012
+ }
1013
+
1014
+ .from-Sunshine-Red {
1015
+ --tw-gradient-from: #b92b27;
1016
+ --tw-gradient-to: rgb(185 43 39 / 0);
1017
+ --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
1018
+ }
1019
+
1020
  .via-purple-500 {
1021
  --tw-gradient-to: rgb(168 85 247 / 0);
1022
  --tw-gradient-stops: var(--tw-gradient-from), #a855f7, var(--tw-gradient-to);
 
1042
  --tw-gradient-stops: var(--tw-gradient-from), #F1A089, var(--tw-gradient-to);
1043
  }
1044
 
 
 
 
 
 
1045
  .via-Happy-Indego-Purple {
1046
  --tw-gradient-to: rgb(148 98 233 / 0);
1047
  --tw-gradient-stops: var(--tw-gradient-from), #9462E9, var(--tw-gradient-to);
 
1093
  --tw-gradient-to: #319B72;
1094
  }
1095
 
1096
+ .to-Amethyst-Dark {
1097
+ --tw-gradient-to: #6E48AA;
1098
+ }
1099
+
1100
+ .to-Peach-Yello {
1101
+ --tw-gradient-to: #FFEDBC;
1102
+ }
1103
+
1104
+ .to-Deep-Space-Gray {
1105
+ --tw-gradient-to: #434343;
1106
+ }
1107
+
1108
+ .to-Sunshine-Blue {
1109
+ --tw-gradient-to: #1565C0;
1110
+ }
1111
+
1112
  .p-5 {
1113
  padding: 1.25rem;
1114
  }
 
1149
  padding-bottom: 0.5rem;
1150
  }
1151
 
1152
+ .px-6 {
1153
+ padding-left: 1.5rem;
1154
+ padding-right: 1.5rem;
1155
+ }
1156
+
1157
  .pt-8 {
1158
  padding-top: 2rem;
1159
  }
 
1182
  padding-top: 0.5rem;
1183
  }
1184
 
1185
+ .pb-3 {
1186
+ padding-bottom: 0.75rem;
1187
+ }
1188
+
1189
  .text-left {
1190
  text-align: left;
1191
  }
 
1245
  color: rgb(0 0 0 / var(--tw-text-opacity));
1246
  }
1247
 
1248
+ .underline {
1249
+ -webkit-text-decoration-line: underline;
1250
+ text-decoration-line: underline;
1251
+ }
1252
+
1253
  .shadow-lg {
1254
  --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
1255
  --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
 
1321
  color: rgb(148 163 184 / var(--tw-text-opacity));
1322
  }
1323
 
1324
+ .placeholder\:text-transparent::-webkit-input-placeholder {
1325
+ color: transparent;
1326
+ }
1327
+
1328
+ .placeholder\:text-transparent::placeholder {
1329
+ color: transparent;
1330
+ }
1331
+
1332
  @-webkit-keyframes pulse {
1333
  50% {
1334
  opacity: .5;
frontend/src/css/iframe.css DELETED
@@ -1,5 +0,0 @@
1
- .Iframe_class{
2
- position: absolute;
3
- width: 100%!important;
4
- height: 100%!important;
5
- }
 
 
 
 
 
 
frontend/src/helper/visual.js CHANGED
@@ -1,38 +1,41 @@
1
  import '../css/dist/output.css'
2
- const emote = ['πŸ‘Ί', 'πŸ‘Ύ', 'πŸ€–', '🧠', '🦾', '🦊', '🐡', 'πŸ¦„', 'πŸ€„' ,'🌟', 'πŸ–₯', 'πŸ“Ÿ', '🧬', 'πŸš€', '🌈', '🌱', '🌎']
3
 
4
- const colour_map = {
5
- 0 : 'bg-gradient-to-bl from-Retro-light-blue to-Retro-light-pink',
6
- 1 : 'bg-gradient-to-bl from-Vapor-Violet to-Vapor-Orange',
7
- 2 : 'bg-gradient-to-bl from-Retro-purple to-Vapor-Pink',
8
- 3 : 'bg-gradient-to-bl from-Retro-purple to-Vapor-Blue',
9
- 4 : 'bg-gradient-to-bl from-Retro-light-pink to-Vapor-Blue',
10
- 5 : 'bg-gradient-to-bl from-indigo-500 via-purple-500 to-pink-500',
11
- 6 : 'bg-gradient-to-bl from-Vapor-Rose to-Vapor-Blue',
12
- 7 : 'bg-gradient-to-bl from-Warm-Blue via-Warm-Pink via-Warm-Red via-Warm-Orange to-Warm-Yellow',
13
- 8 : 'bg-gradient-to-bl from-Happy-Yellow via-Happy-Tangerine via-Happy-Light-Magenta via-Happy-Indego-Purple via-Cool-Blue to-Happy-Sea-Blue',
14
- 9 : 'bg-gradient-to-bl from-Blue-Turquoise via-Blue-Midtone to-Blue-Royal',
15
- 10 : 'bg-gradient-to-bl from-Green-Black via-Green-Forest to-Green-Emerald'
16
- }
 
 
 
 
17
 
18
  /**
19
- *
20
- * "Warm-Blue": "#283AB8",
21
- "Warm-Violet" : "#8D379E",
22
- "Warm-Pink" : "#F13484",
23
- "Warm-Red" : "#FF605D",
24
- "Warm-Orange" : "#FEA959",
25
- "Warm-Yellow" : "#FEE27A",
26
  */
27
-
28
  export const random_emoji = () =>{
29
  return emote[Math.floor(Math.random() * emote.length)]
30
  }
31
 
 
 
 
 
32
  export const random_colour = () => {
33
- return colour_map[Math.floor(Math.random() * Object.keys(colour_map).length)]
34
  }
35
 
 
36
  export const list_of_null = (idx) => {
37
  var list = []
38
  for(var i = 0; i < idx; i++ ) {
@@ -41,8 +44,11 @@ export const list_of_null = (idx) => {
41
  return list
42
  }
43
 
44
-
 
 
 
45
  export const useThemeDetector = () => {
46
  const getCurrentTheme = () => window.matchMedia("(prefers-color-scheme: dark)").matches;
47
- return getCurrentTheme;
48
  }
 
1
  import '../css/dist/output.css'
2
+ const emote = ['πŸ‘Ί','πŸ’€','πŸŽ‰','πŸ‘Ύ','πŸ€–','πŸ”₯','🧠','🌿','🦾','🦊','✨','🏑','🐡','πŸ¦„','πŸ€„','🌟','πŸ–₯','πŸ“Ÿ','πŸ‘‹','🧬','πŸ“–','πŸš€','πŸ‘‘','🌈','🌱','🌎']
3
 
4
+ const colour_map = [
5
+ 'bg-gradient-to-bl from-Retro-light-blue to-Retro-light-pink',
6
+ 'bg-gradient-to-bl from-Vapor-Violet to-Vapor-Orange',
7
+ 'bg-gradient-to-bl from-Retro-purple to-Vapor-Pink',
8
+ 'bg-gradient-to-bl from-Retro-purple to-Vapor-Blue',
9
+ 'bg-gradient-to-bl from-Retro-light-pink to-Vapor-Blue',
10
+ 'bg-gradient-to-bl from-indigo-500 via-purple-500 to-pink-500',
11
+ 'bg-gradient-to-bl from-Vapor-Rose to-Vapor-Blue',
12
+ 'bg-gradient-to-bl from-Warm-Blue via-Warm-Pink via-Warm-Red via-Warm-Orange to-Warm-Yellow',
13
+ 'bg-gradient-to-bl from-Happy-Yellow via-Happy-Tangerine via-Happy-Indego-Purple via-Cool-Blue to-Happy-Sea-Blue',
14
+ 'bg-gradient-to-bl from-Blue-Turquoise via-Blue-Midtone to-Blue-Royal',
15
+ 'bg-gradient-to-bl from-Green-Black via-Green-Forest to-Green-Emerald',
16
+ 'bg-gradient-to-bl from-Amethyst-Light to-Amethyst-Dark',
17
+ 'bg-gradient-to-bl from-Peach-Red to-Peach-Yello',
18
+ 'bg-gradient-to-bl from-Deep-Space-Black to-Deep-Space-Gray',
19
+ 'bg-gradient-to-bl from-Sunshine-Red to-Sunshine-Blue'
20
+ ]
21
 
22
  /**
23
+ * Get a random emoji from emote array
24
+ * @returns random emoji from emote array
 
 
 
 
 
25
  */
 
26
  export const random_emoji = () =>{
27
  return emote[Math.floor(Math.random() * emote.length)]
28
  }
29
 
30
+ /**
31
+ * Get a random color string from colour_map array
32
+ * @returns random color css string
33
+ */
34
  export const random_colour = () => {
35
+ return colour_map[Math.floor(Math.random() * colour_map.length)]
36
  }
37
 
38
+
39
  export const list_of_null = (idx) => {
40
  var list = []
41
  for(var i = 0; i < idx; i++ ) {
 
44
  return list
45
  }
46
 
47
+ /**
48
+ *
49
+ * @returns
50
+ */
51
  export const useThemeDetector = () => {
52
  const getCurrentTheme = () => window.matchMedia("(prefers-color-scheme: dark)").matches;
53
+ return getCurrentTheme();
54
  }
frontend/tailwind.config.js CHANGED
@@ -7,6 +7,14 @@ module.exports = {
7
  extend: {
8
 
9
  colors : {
 
 
 
 
 
 
 
 
10
  "Retro-light-blue" : "#2de2e6",
11
  "Retro-dark-blue" : "#035ee8",
12
  "Retro-light-pink" : "#f6019d",
 
7
  extend: {
8
 
9
  colors : {
10
+ "Amethyst-Light" : "#9D50BB",
11
+ "Amethyst-Dark" : "#6E48AA",
12
+ "Peach-Red" : "#ED4264",
13
+ "Peach-Yello" : "#FFEDBC",
14
+ "Deep-Space-Black" : "#000000",
15
+ "Deep-Space-Gray" : "#434343",
16
+ "Sunshine-Red" : "#b92b27",
17
+ "Sunshine-Blue" : "#1565C0",
18
  "Retro-light-blue" : "#2de2e6",
19
  "Retro-dark-blue" : "#035ee8",
20
  "Retro-light-pink" : "#f6019d",
images/application_dark.png CHANGED

Git LFS Details

  • SHA256: 184647a1a319f86ffe49539cf19a512cd8e27d2d1d3e93ad7c16f4ba7056bd35
  • Pointer size: 131 Bytes
  • Size of remote file: 375 kB

Git LFS Details

  • SHA256: 8cf5fba076c8b2880ad4a4603528bbdc6c40ef5768133ae6f93392a3507e1b62
  • Pointer size: 131 Bytes
  • Size of remote file: 762 kB
images/application_light.png CHANGED

Git LFS Details

  • SHA256: 98c43f8327663b4b704045feb0b7c1d9f3ec917d7469f30079cedc22b8551f4a
  • Pointer size: 131 Bytes
  • Size of remote file: 409 kB

Git LFS Details

  • SHA256: 4523f8e4e5c4fbbb3c761bef516c716eaaf9ae247f3751f2f405d479130a37fc
  • Pointer size: 131 Bytes
  • Size of remote file: 776 kB