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} ); case "progress": return ( {this.props.message} ); case "link": return ( {this.props.message} ); case "error": return (
{this.props.message}
); 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 LogDisplay extends React.Component { render() { if (!this.props.logContent) { return ; } return (
{this.props.logContent}
); } } 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: [], logContent: "", 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) { if (message.action === "log") { this.setState((state) => ({ logContent: state.logContent + message.message + "\n", })); return; } this.setState((state) => ({ messages: [...state.messages, message] })); if (message.action === "app-label") { this.setState((_state) => ({ appName: message.message, logContent: "" })); } 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, logContent: "" })); 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; const maxReconnectDelay = 10; // 10 seconds const timeoutInSeconds = (that.timeout * 2) / 1000; const reconnectDelay = Math.min(maxReconnectDelay, timeoutInSeconds); // 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 ${reconnectDelay} seconds.`); 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"));