Spaces:
Configuration error
Configuration error
File size: 11,624 Bytes
0563a7e 7736a4b 0563a7e 7736a4b 0563a7e 7736a4b 83e5165 0563a7e 83e5165 0563a7e 7736a4b 0563a7e 83e5165 0563a7e 83e5165 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
import React, { Component } from "react";
import { Icon } from 'semantic-ui-react'
import Import from '../Modal/importer'
import { random_colour, random_emoji } from "../../helper/visual";
import "../../css/dist/output.css"
import {BsArrowLeftShort} from 'react-icons/bs';
import {ReactComponent as ReactLogo} from '../../images/logo.svg'
export default class Navbar extends Component{
constructor(props){
super(props)
this.temp_host = 0
this.deleteNode = props.onDelete
this.state = {
open : true,
menu : [],
colour : props.colour || [],
text : "",
name : "",
emoji : props.emoji || [],
mode : false,
modal : false,
error : false
}
}
componentDidMount(){
this.fetch_classes()
}
/**
* Asynchronously call the Flask api server every second to check if there exist a gradio application info
* @return null
*/
fetch_classes = async () => {
try {
setInterval( async () => {
await fetch("http://localhost:2000/api/open/ports", { method: 'GET', mode : 'cors',})
.then(response => response.json())
.then(data => {
this.handelTabs(this.state.menu,data, data)
this.setState({menu : data})
})
.catch(error => {console.log(error)})
},1000);
}catch(e){
console.log(e)
}
}
/**
* Append new node from the user
*/
appendStreamNode = async (type) => {
const pattern = {
local : new RegExp('^https?://(localhost)(:[0-9]+)?(/)?$'),
share : new RegExp('^https?://(?:[a-zA-Z0-9]+\\.gradio\\.live)/?$'),
huggingFace: new RegExp('^https?://([a-zA-Z0-9-]+\\.hf\\.space)/?$'),
proxmoxVNC: new RegExp('^wss?://([a-zA-Z0-9-]+\\.yourdomain\\.com)/?$') // Regex pattern for Proxmox VNC URLs
}
if (this.state.name.length > 20 ||
this.state.text === ""||
this.state.menu.findIndex(element => {return element.name.toLowerCase() === this.state.name.toLowerCase() || element.host.includes(this.state.text) }) !== -1 ||
this.state.text.includes(" ") ||
(!pattern.local.test(this.state.text) &&
!pattern.share.test(this.state.text) &&
!pattern.huggingFace.test(this.state.text) &&
!pattern.proxmoxVNC.test(this.state.text))){
this.setState({
'text': '',
'name': '',
'error': true})
return
}
fetch(this.state.text, {method: "GET", mode: 'no-cors'}).then((re) => {
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 => {
this.setState({'text': "",'name' : "",'error' : false,'modal' : false })
}).catch(() => this.setState({'text': '', 'name' : '', 'error' : true, }))
}).catch((err)=> this.setState({'text': '','name' : '', 'error' : true,}))
}
/**
* Render a tab for the Proxmox VNC that can be dragged into React Flow
*/
renderProxmoxVncTab = () => {
// Assuming the Proxmox VNC tab information is stored in the state
const { proxmoxVncInfo } = this.state;
if (!proxmoxVncInfo) return null; // If no Proxmox VNC info, don't render anything
return (
<li onDragStart={(event) => this.onDragStart(event, 'proxmoxVNC', proxmoxVncInfo, -1)}
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"
draggable>
<div className="absolute -mt-2 text-4xl opacity-60 z-10">{random_emoji()}</div>
<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)"}}>
Proxmox VNC
</h4>
</li>
);
}
/**
* error check the user input
* @param {*} bool boolean of the current state of the modal
*/
handelModal = (bool) => {
this.setState({'error' : !bool ? false : this.state.error ,
'modal' : bool})
}
/**
* when dragged get all the information needed
* @param {*} event
* @param {*} nodeType string 'custom' node type
* @param {*} item object information returned from the api
* @param {*} index current index
*/
onDragStart = (event, nodeType, item, index) => {
event.dataTransfer.setData('application/reactflow', nodeType);
event.dataTransfer.setData('application/style', JSON.stringify({colour : this.state.colour[index], emoji : this.state.emoji[index] }))
event.dataTransfer.setData('application/item', JSON.stringify(item))
event.dataTransfer.effectAllowed = 'move';
};
/**
* droped event that occurs when the user drops the Tab within the tash div.
* The function just deletes all nodes within React-Flow enviorment related,
* and remove it from the api.
* @param {*} e drop event
*/
onDragDrop = (e) => {
e.preventDefault();
var item = JSON.parse(e.dataTransfer.getData('application/item'));
fetch("http://localhost:2000/api/remove/port", {method : "POST", mode: 'cors', headers : { 'Content-Type' : 'application/json' }, body: JSON.stringify(item) }).then((re)=>{
this.deleteNode(item.name)
})
}
/**
* update the tabs within the navbar
* @param {*} e current menu
* @param {*} d integer variable of the diffence between the current menu and new menu updated ment
*/
handelTabs = async (e, d) => {
// if less then 0 we must remove colour's and emoji's
// get index of the object
// remove
var c = []
var j = []
if (d.length - e.length === 0) return
else if(d.length - e.length < 0){
var a = this.state.menu.filter(item => e.includes(item)) // get the items not in menu anymore
c = this.state.colour
j = this.state.emoji
for(var k=0; k < d.length; k++){
c.splice(this.state.menu.indexOf(a[k]), 1)
j.splice(this.state.menu.indexOf(a[k]), 1)
}
this.setState({'colour' : c, 'emoji' : j})
}else{
//append new colours
for(var i =0; i < d.length; i++){
c.push(random_colour(i === 0 ? null : c[i-1]));
j.push(random_emoji(i === 0 ? null : c[i-1]));
}
const colour = [...this.state.colour]
const emoji = [...this.state.emoji]
this.setState({'colour' : [...colour, ...c], 'emoji' : [...emoji, ...j],})
}
}
handelError = (boolean) => {
this.setState({'error' : boolean})
}
/**
* handel navagation open and close function
*/
handelNavbar = () => {
this.setState({'open' : !this.state.open})
}
/**
*
* @param {*} e : event type to get the target value of the current input
* @param {*} type : text | name string that set the changed value of the input to the current value
*/
updateText = (e, type) => {
this.setState({[`${type}`] : e.target.value })
}
/**
*
* @param {*} item : object infomation from the flask api
* @param {*} index : current index with in the list
* @returns div component that contians infomation of gradio
*/
subComponents(item, index){
return(<>
<li key={`${index}-li`} onDragStart={(event) => this.onDragStart(event, 'custom', item, index)}
className={` text-white text-md flex flex-col text-center items-center cursor-grab shadow-lg
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>
<div key={`${index}-div`} className=" absolute -mt-2 text-4xl opacity-60 z-10 ">{`${this.state.emoji[index] === null ? "" : this.state.emoji[index]}`}</div>
<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>
</li >
</>)
}
render(){
return (<div>
<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`} >
<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 `}/>
<div className="inline-flex w-full">
<h1 className={`font-sans font-bold text-lg ${this.state.open ? "" : "hidden"} duration-500 ml-auto mr-auto`}> <ReactLogo className="w-9 h-9 ml-auto mr-auto"/> Gradio Flow </h1>
</div>
<div className={`rounded-md text-center ${this.state.open ? "" : "px-0"} py-3`} onClick={() => {this.handelModal(true)}}>
<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`}>
<Icon className=" block mr-auto ml-auto" name="plus"/>
</div>
</div>
<Import open={this.state.modal}
quitHandeler={this.handelModal}
textHandler={this.updateText}
appendHandler={this.appendStreamNode}
handelError={this.handelError}
catch={this.state.error}/>
<div className=" relative z-10 h-auto overflow-auto pt-4">
<ul className="pt-2">
{this.state.menu.map((menu, index) => {return this.subComponents(menu, index)})}
</ul>
</div>
<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)}}>
<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`}>
<Icon name='trash alternate' />
</div>
</div>
</div>
</div>)
}
}
|