let storage = new Storage(); class SearchBar extends React.Component { constructor(props) { super(props); this.handleInputChange = this.handleInputChange.bind(this); this.handleSnapshotToggle = this.handleSnapshotToggle.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleInputChange(event) { this.props.onSearchInput(event.target.value); } handleSnapshotToggle(event) { this.props.onSnapshotToggle(event); } handleSubmit(event) { this.props.onSearchSubmit(event); } render() { let btn = Generate if (this.props != null && this.props.appName != null) { btn = } return ( {btn} ); } } class DeleteAppButton extends React.Component { render() { return ( Delete {this.props.appName} ) } } class Message extends React.Component { render() { var variants = { "status": "info", "progress": "info", "failure": "danger", "done": "success" } switch (this.props.action) { case 'done': case 'failure': case 'status': return ( {this.props.message} ) break; case 'progress': return ( {this.props.message} ) break; case 'link': return ( {this.props.message} ) break; case 'error': return (
              {this.props.message}
            
) break; default: return ( ) } } } class ResourceQuotaStatus extends React.Component { render() { if (this.props === null || this.props.resourceQuota === null) { return ( ) } let used = this.props.resourceQuota.used; let hard = this.props.resourceQuota.hard; if (typeof used == "undefined" || typeof hard == "undefined") { return ( ) } return (
Current resource quota
) } } class Status extends React.Component { render() { if (this.props.messages.length == 0) { return ( ); } else { return (
{ this.props.messages.map(item => ) }
); } } } class AppsList extends React.Component { render() { let appCount = Object.keys(this.props.apps).length; if (appCount === 0) { return false; } let header =

Currently running Prometheus instances

let apps = Object.keys(this.props.apps).map(k => { return ( {k} { this.props.onDeleteApp(k) }} appName={k} /> ) }) return
{header} {apps}
} } class SearchForm extends React.Component { constructor(props) { super(props); this.state = { querySearch: '', searchInput: '', snapshotToggle: false, messages: [], appName: null, apps: storage.getData(), ws: null, resourceQuota: { used: 0, hard: 0, } }; this.handleSearchInput = this.handleSearchInput.bind(this); this.handleSnapshotToggle = this.handleSnapshotToggle.bind(this); this.handleSearchSubmit = this.handleSearchSubmit.bind(this); this.handleDeleteAppInternal = this.handleDeleteAppInternal.bind(this); this.handleDeleteApp = this.handleDeleteApp.bind(this); this.handleDeleteCurrentApp = this.handleDeleteCurrentApp.bind(this); this.addMessage = this.addMessage.bind(this); this.sendWSMessage = this.sendWSMessage.bind(this); this.connect = this.connect.bind(this); this.check = this.check.bind(this); this.search = this.search.bind(this); } handleSearchInput(searchInput) { this.setState({searchInput: searchInput}); } handleSnapshotToggle(event) { this.setState({snapshotToggle: !this.state.snapshotToggle}) } handleSearchSubmit(event) { event.preventDefault(); let query = this.state.searchInput; if (query.length == 0) { return; } try { let url = new URL(query); if (this.state.snapshotToggle) { url.searchParams.append('altsnap', "true"); } this.search(url.toString()); } catch (e) { console.log(e); } } sendWSMessage(message) { // add messages to queue if connection is not ready if (!this.state.ws || this.state.ws.readyState != WebSocket.OPEN) { if (this.state.ws) { console.log("ws.readyState " + this.state.ws.readyState); } if (!this.ws_msgs) this.ws_msgs = [] console.log("Added message " + message + " to queue"); this.ws_msgs.push(message) } else { console.log("Sending message " + message); this.state.ws.send(message) } } search(input) { try { this.state.messages = []; this.sendWSMessage(JSON.stringify({ 'action': 'new', 'message': input, })); } catch (error) { console.log(error); } } handleDeleteApp(appName) { console.log(appName) if (this.state.appName === appName) { this.handleDeleteCurrentApp() } else { this.handleDeleteAppInternal(appName) } } handleDeleteCurrentApp() { this.handleDeleteAppInternal(this.state.appName) // Remove message with app-label from the list let newMessages = this.state.messages.slice(1, this.state.messages.length) this.setState(state => ({ messages: newMessages, appName: null, })) } handleDeleteAppInternal(appName) { try { this.sendWSMessage(JSON.stringify({ 'action': 'delete', 'message': appName })) storage.removeInstance(appName) this.setState(state => ({ apps: storage.getData(), })) } catch (error) { console.log(error) } } addMessage(message) { this.setState(state => ({messages: [...state.messages, message]})) if (message.action === "app-label") { this.setState(state => ({appName: message.message})) } if (message.action === "done" || message.action === "error" || message.action === "failure") { // Remove message with progress from the list let newMessages = this.state.messages.filter(function (message) { return message.action != "progress"; }); this.setState(state => ({messages: newMessages})) if (message.data != null) { storage.addInstance(message.data.hash, message.data.url) } this.setState(state => ({apps: storage.getData()})) } if (message.action === "rquota") { let rquotaStatus = JSON.parse(message.message) this.setState(state => ({ resourceQuota: { used: rquotaStatus.used, hard: rquotaStatus.hard, } })) } } check() { const {ws} = this.state; if (!ws || ws.readyState == WebSocket.CLOSED) this.connect(); //check if websocket instance is closed, if so call `connect` function. }; connect() { var loc = window.location; var ws_uri; if (loc.protocol === "https:") { ws_uri = "wss:"; } else { ws_uri = "ws:"; } ws_uri += "//" + loc.host; ws_uri += "/ws/status"; var ws = new WebSocket(ws_uri); let that = this; var connectInterval; // websocket onopen event listener ws.onopen = () => { console.log("websocket connected"); that.setState({ws: ws}); that.timeout = 250; // reset timer to 250 on open of websocket connection clearTimeout(connectInterval); // clear Interval on on open of websocket connection // Send messages if there's a queue ws.send(JSON.stringify({"action": "connect"})) while (that.ws_msgs && that.ws_msgs.length > 0) { ws.send(that.ws_msgs.pop()) } }; // websocket onclose event listener ws.onclose = e => { console.log( `Socket is closed. Reconnect will be attempted in ${Math.min( 10000 / 1000, (that.timeout + that.timeout) / 1000 )} second.`, e.reason ); that.timeout = that.timeout + that.timeout; //increment retry interval connectInterval = setTimeout(this.check, Math.min(10000, that.timeout)); //call check function after timeout }; // websocket onerror event listener ws.onerror = err => { console.error( "Socket encountered error: ", err.message, "Closing socket" ); ws.close(); }; ws.onmessage = evt => { console.log("Received " + evt.data); const message = JSON.parse(evt.data); this.addMessage(message) } this.setState({ws: ws}); } componentDidMount() { window.addEventListener("beforeunload", this.onUnload); this.check(); this.timeout = 0; if (!this.state.searchInput) { let params = (new URL(window.location)).searchParams; let searchInput = params.get('search'); if (searchInput && searchInput != this.state.querySearch) { this.state.querySearch = searchInput; this.handleSearchInput(searchInput); this.search(searchInput); } } } onUnload() { if (this.state.ws) { console.log("Closing socket"); this.state.ws.close(); } } componentWillUnmount() { window.removeEventListener("beforeunload", this.onUnload); } render() { let messages; let searchClass; if (this.state.appName != null) { messages = searchClass = null; } else { messages = []; searchClass = 'search-center'; } return (

PromeCIeus


{messages}
); } } ReactDOM.render( , document.getElementById('container') );